diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..f6cce320
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+vault-agent-sidecar/.DS_Store
diff --git a/0-nginx-all.yaml b/0-nginx-all.yaml
new file mode 100644
index 00000000..b53a546c
--- /dev/null
+++ b/0-nginx-all.yaml
@@ -0,0 +1,87 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: nginx
+ name: nginx
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: nginx
+ template:
+ metadata:
+ labels:
+ app: nginx
+ spec:
+ containers:
+ - image: nginx
+ name: nginx
+ ports:
+ - containerPort: 80
+ protocol: TCP
+ #changed https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#example-1
+ resources:
+ requests:
+ memory: "64Mi"
+ cpu: "250m"
+ limits:
+ memory: "128Mi"
+ cpu: "500m"
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: nginx
+spec:
+ ports:
+ - port: 80
+ protocol: TCP
+ targetPort: 80
+ selector:
+ app: nginx
+ sessionAffinity: None
+ type: LoadBalancer
+---
+# Ingress resource example changed
+
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: nginx
+ annotations:
+ nginx.ingress.kubernetes.io/rewrite-target: /
+spec:
+ ingressClassName: nginx-example
+ rules:
+ - http:
+ paths:
+ - path: /testpath
+ pathType: Prefix
+ backend:
+ service:
+ name: test
+ port:
+ number: 80
+
+#older example
+
+# apiVersion: extensions/v1beta1
+# kind: Ingress
+# metadata:
+# name: nginx
+# annotations:
+# ingress.kubernetes.io/ssl-redirect: "false"
+# spec:
+# rules:
+# - http:
+# paths:
+# - path: /
+# backend:
+# serviceName: nginx
+# servicePort: 80
+
+# https://kubernetes.io/docs/reference/using-api/deprecation-guide/#ingress-v122
+# Ingress resource example is replaced with this: https://kubernetes.io/docs/concepts/services-networking/ingress/#the-ingress-resource
\ No newline at end of file
diff --git a/0-nginx-configmap.yaml b/0-nginx-configmap.yaml
new file mode 100644
index 00000000..30ae2191
--- /dev/null
+++ b/0-nginx-configmap.yaml
@@ -0,0 +1,20 @@
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: nginx
+ labels:
+ name: nginx
+spec:
+ containers:
+ - name: nginx
+ image: nginx:1.12-alpine
+ command: [ "/bin/sh", "-c", "env" ] #changed so we can run **k logs nginx** to see configmap data.
+ ports:
+ - containerPort: 80
+ envFrom:
+ - configMapRef:
+ name: kubernauts
+ restartPolicy: Never
+
+
diff --git a/0-nginx-deployment.yaml b/0-nginx-deployment.yaml
new file mode 100644
index 00000000..ac9a61a7
--- /dev/null
+++ b/0-nginx-deployment.yaml
@@ -0,0 +1,23 @@
+---
+ apiVersion: apps/v1
+ kind: Deployment
+ metadata:
+ labels:
+ app: nginx
+ name: nginx
+ spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: nginx
+ template:
+ metadata:
+ labels:
+ app: nginx
+ spec:
+ containers:
+ - image: nginx
+ name: nginx
+ ports:
+ - containerPort: 80
+ protocol: TCP
\ No newline at end of file
diff --git a/0-nginx-ingress.yaml b/0-nginx-ingress.yaml
new file mode 100644
index 00000000..6f65f05f
--- /dev/null
+++ b/0-nginx-ingress.yaml
@@ -0,0 +1,35 @@
+---
+# old code commented out #changed
+# apiVersion: extensions/v1beta1
+# kind: Ingress
+# metadata:
+# name: nginx
+# annotations:
+# ingress.kubernetes.io/ssl-redirect: "false"
+# spec:
+# rules:
+# - http:
+# paths:
+# - path: /
+# backend:
+# serviceName: nginx
+# servicePort: 80
+
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: nginx
+ annotations:
+ nginx.ingress.kubernetes.io/ssl-redirect: "false"
+spec:
+ ingressClassName: nginx-example
+ rules:
+ - http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: nginx
+ port:
+ number: 80
\ No newline at end of file
diff --git a/0-nginx-service.yaml b/0-nginx-service.yaml
new file mode 100644
index 00000000..852a6cfd
--- /dev/null
+++ b/0-nginx-service.yaml
@@ -0,0 +1,50 @@
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: nginx
+spec:
+ ports:
+ - port: 80
+ protocol: TCP
+ targetPort: 80
+ selector:
+ app: nginx
+ sessionAffinity: None
+ type: ClusterIP
+---
+# changed
+# apiVersion: extensions/v1beta1
+# kind: Ingress
+# metadata:
+# name: nginx
+# annotations:
+# ingress.kubernetes.io/ssl-redirect: "false"
+# spec:
+# rules:
+# - http:
+# paths:
+# - path: /
+# backend:
+# serviceName: nginx
+# servicePort: 80
+
+
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: nginx
+ annotations:
+ nginx.ingress.kubernetes.io/ssl-redirect: "false"
+spec:
+ ingressClassName: nginx-example
+ rules:
+ - http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: nginx
+ port:
+ number: 80
\ No newline at end of file
diff --git a/1-whoami-deployment.yaml b/1-whoami-deployment.yaml
new file mode 100644
index 00000000..29d643b8
--- /dev/null
+++ b/1-whoami-deployment.yaml
@@ -0,0 +1,17 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: whoami-deployment
+spec:
+ replicas: 2
+ selector:
+ matchLabels:
+ app: whoami
+ template:
+ metadata:
+ labels:
+ app: whoami
+ spec:
+ containers:
+ - name: whoami-container
+ image: containous/whoami
diff --git a/1-whoami-ingress.yaml b/1-whoami-ingress.yaml
new file mode 100644
index 00000000..8e288fec
--- /dev/null
+++ b/1-whoami-ingress.yaml
@@ -0,0 +1,38 @@
+# changed
+# apiVersion: extensions/v1beta1
+# kind: Ingress
+# metadata:
+# name: whoami-ingress
+# annotations:
+# kubernetes.io/ingress.class: nginx
+# # traefik.ingress.kubernetes.io/rule-type: "PathPrefixStrip"
+# spec:
+# rules:
+# - host: csky08
+# http:
+# paths:
+# - path: /
+# backend:
+# serviceName: whoami-service
+# servicePort: 80
+
+
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: whoami-ingress
+ annotations:
+ ingressclass.kubernetes.io/is-default-class: "true"
+spec:
+ ingressClassName: nginx
+ rules:
+ - host: csky08
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: whoami-service
+ port:
+ number: 80
\ No newline at end of file
diff --git a/1-whoami-service-ClusterIP.yaml b/1-whoami-service-ClusterIP.yaml
new file mode 100644
index 00000000..933d1d1c
--- /dev/null
+++ b/1-whoami-service-ClusterIP.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: whoami-service
+spec:
+ ports:
+ - name: http
+ targetPort: 80
+ port: 80
+ selector:
+ app: whoami
+ type: ClusterIP
diff --git a/1-whoami-service-loadbalancer.yaml b/1-whoami-service-loadbalancer.yaml
new file mode 100644
index 00000000..e6c518b2
--- /dev/null
+++ b/1-whoami-service-loadbalancer.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Service
+metadata:
+ #name: whoami-service-loadbalancer #changed
+ name: whoami-service
+spec:
+ ports:
+ - name: http
+ targetPort: 80
+ port: 80
+ selector:
+ app: whoami
+ type: LoadBalancer
diff --git a/1-whoami-service-nodeport.yaml b/1-whoami-service-nodeport.yaml
new file mode 100644
index 00000000..27c0b4ed
--- /dev/null
+++ b/1-whoami-service-nodeport.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Service
+metadata:
+ #name: whoami-service-nodeport #changed
+ name: whoami-service
+spec:
+ ports:
+ - name: http
+ targetPort: 80
+ port: 80
+ selector:
+ app: whoami
+ type: NodePort
diff --git a/2-whoareyou-all.yml b/2-whoareyou-all.yml
new file mode 100644
index 00000000..76a3cc0e
--- /dev/null
+++ b/2-whoareyou-all.yml
@@ -0,0 +1,71 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: whoareyou-deployment
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: whoareyou
+ template:
+ metadata:
+ labels:
+ app: whoareyou
+ spec:
+ containers:
+ - name: whoareyou-container
+ image: containous/whoami
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: whoareyou-service
+spec:
+ ports:
+ - name: http
+ targetPort: 80
+ port: 80
+ selector:
+ app: whoareyou
+---
+# changed
+# apiVersion: extensions/v1beta1
+# kind: Ingress
+# metadata:
+# name: whoareyou-ingress
+# annotations:
+# kubernetes.io/ingress.class: "traefik"
+# spec:
+# rules:
+# - host: node2
+# http:
+# paths:
+# - path: /
+# backend:
+# serviceName: whoareyou-service
+# servicePort: http
+
+
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: whoareyou-ingress
+ annotations:
+ ingressclass.kubernetes.io/is-default-class: "true"
+spec:
+ ingressClassName: traefik
+ rules:
+ - host: node2
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: whoareyou-service
+ port:
+ number: 80
+
+# Do we need to add IngreessClass https://kubernetes.github.io/ingress-nginx/#i-have-only-one-instance-of-the-ingresss-nginx-controller-in-my-cluster-what-should-i-do
+
+
diff --git a/2-whoareyou-svc-headless.yaml b/2-whoareyou-svc-headless.yaml
new file mode 100644
index 00000000..f4b94582
--- /dev/null
+++ b/2-whoareyou-svc-headless.yaml
@@ -0,0 +1,25 @@
+apiVersion: v1
+kind: Service
+metadata:
+ #creationTimestamp: "2020-02-15T12:30:22Z" #changed
+ name: whoareyou-service
+ namespace: default
+ # changed
+ #resourceVersion: "1343711"
+ #changed https://www.weave.works/blog/what-you-should-know-about-kubernetes-1-20#:~:text=The%20SelfLink%20field%20in%20every,beginning%20of%20the%20deprecation%20process.
+ #selfLink: /api/v1/namespaces/default/services/whoareyou-service
+ #uid: f8221615-bb4f-4b11-9f07-733eb53a155c
+spec:
+ clusterIP: None
+ ports:
+ - name: http
+ port: 80
+ protocol: TCP
+ targetPort: 80
+ selector:
+ app: whoareyou
+ sessionAffinity: None
+ type: ClusterIP
+# changed
+# status:
+# loadBalancer: {}
diff --git a/2048-game/2048-deployment.yaml b/2048-game/2048-deployment.yaml
new file mode 100644
index 00000000..58fe4a33
--- /dev/null
+++ b/2048-game/2048-deployment.yaml
@@ -0,0 +1,24 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: "2048"
+ name: "2048-deployment"
+ namespace: 2048-game
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: "2048"
+ template:
+ metadata:
+ labels:
+ app: "2048"
+ spec:
+ containers:
+ - image: alexwhen/docker-2048
+ imagePullPolicy: Always
+ name: docker-2048
+ ports:
+ - containerPort: 80
diff --git a/2048-game/2048-ingress.yaml b/2048-game/2048-ingress.yaml
new file mode 100644
index 00000000..eaa21f45
--- /dev/null
+++ b/2048-game/2048-ingress.yaml
@@ -0,0 +1,20 @@
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ name: "2048-ingress"
+ namespace: "2048-game"
+ annotations:
+ # for k3s:
+ kubernetes.io/ingress.class: traefik
+ # on aws with alb
+ # alb.ingress.kubernetes.io/scheme: internet-facing
+ labels:
+ app: 2048-ingress
+spec:
+ rules:
+ - http:
+ paths:
+ - path: /*
+ backend:
+ serviceName: "service-2048"
+ servicePort: 80
diff --git a/2048-game/2048-namespace.yaml b/2048-game/2048-namespace.yaml
new file mode 100644
index 00000000..08a35c69
--- /dev/null
+++ b/2048-game/2048-namespace.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: "2048-game"
diff --git a/2048-game/2048-service.yaml b/2048-game/2048-service.yaml
new file mode 100644
index 00000000..176d4b7a
--- /dev/null
+++ b/2048-game/2048-service.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: "service-2048"
+ namespace: "2048-game"
+spec:
+ ports:
+ - port: 80
+ targetPort: 80
+ protocol: TCP
+ type: NodePort
+ # type: LoadBalancer
+ selector:
+ app: "2048"
diff --git a/3-ghost-deployment.yaml b/3-ghost-deployment.yaml
new file mode 100644
index 00000000..e081675a
--- /dev/null
+++ b/3-ghost-deployment.yaml
@@ -0,0 +1,29 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ # changed
+ # annotations:
+ # deployment.kubernetes.io/revision: "1"
+ labels:
+ run: ghost
+ name: ghost
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ run: ghost
+ template:
+ metadata:
+ labels:
+ run: ghost
+ spec:
+ containers:
+ - image: kubernautslabs/ghost:latest
+ imagePullPolicy: IfNotPresent
+ name: ghost
+ resources:
+ limits:
+ memory: 512Mi
+ cpu: 500m
+ requests:
+ memory: 256Mi
diff --git a/3-ghost-ingress-tls.yaml b/3-ghost-ingress-tls.yaml
new file mode 100644
index 00000000..d0778f74
--- /dev/null
+++ b/3-ghost-ingress-tls.yaml
@@ -0,0 +1,68 @@
+---
+#apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: ghost
+ annotations:
+ # kubernetes.io/ingress.class: traefik
+ traefik.ingress.kubernetes.io/router.tls: "true"
+ # ingress.kubernetes.io/ssl-redirect: "true"
+ # kubernetes.io/ingress.class: kong
+ # traefik.ingress.kubernetes.io/frontend-entry-points: http,https
+ # traefik.ingress.kubernetes.io/redirect-entry-point: https
+ # traefik.ingress.kubernetes.io/redirect-permanent: "true"
+spec:
+ # tls:
+ # - hosts:
+ # - my.ghost.svc
+ # - admin.ghost.svc
+ # secretName: ghost-secret
+ tls:
+ - secretName: ghost-secret
+ rules:
+ - host: my.ghost.svc
+ http:
+ paths:
+ - path: /
+ pathType: Prefix #changed
+ backend:
+ #serviceName: ghost
+ service:
+ name: ghost
+ #servicePort: 2368
+ port:
+ number: 2368
+ - host: admin.ghost.svc
+ http:
+ paths:
+ - path: /ghost
+ pathType: Prefix #changed
+ backend:
+ # serviceName: ghost
+ # servicePort: 2368
+ service:
+ name: ghost
+ port:
+ number: 2368
+
+# kind: Ingress
+# apiVersion: networking.k8s.io/v1beta1
+# metadata:
+# name: foo
+# namespace: production
+
+# spec:
+# rules:
+# - host: example.net
+# http:
+# paths:
+# - path: /bar
+# backend:
+# serviceName: service1
+# servicePort: 80
+# # Only selects which certificate(s) should be loaded from the secret, in order to terminate TLS.
+# # Doesn't enable TLS for that ingress (hence for the underlying router).
+# # Please see the TLS annotations on ingress made for that purpose.
+# tls:
+# - secretName: supersecret
\ No newline at end of file
diff --git a/3-ghost-ingress.yaml b/3-ghost-ingress.yaml
new file mode 100644
index 00000000..ff3ad6f1
--- /dev/null
+++ b/3-ghost-ingress.yaml
@@ -0,0 +1,22 @@
+---
+#apiVersion: extensions/v1beta1 #changed
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: ghost
+ annotations:
+ #ingress.kubernetes.io/ssl-redirect: "false" #changed
+ nginx.ingress.kubernetes.io/ssl-redirect: "false"
+spec:
+ rules:
+ - http:
+ paths:
+ - path: /ghost
+ pathType: Prefix
+ backend:
+ # serviceName: ghost
+ # servicePort: 2368
+ service:
+ name: ghost
+ port:
+ number: 2368
diff --git a/3-ghost-svc.yaml b/3-ghost-svc.yaml
new file mode 100644
index 00000000..aeb3591a
--- /dev/null
+++ b/3-ghost-svc.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: ghost
+spec:
+ ports:
+ - name: http
+ targetPort: 2368
+ port: 2368
+ selector:
+ run: ghost
+ type: ClusterIP
\ No newline at end of file
diff --git a/3-tier-app/README.md b/3-tier-app/README.md
new file mode 100644
index 00000000..043b7b95
--- /dev/null
+++ b/3-tier-app/README.md
@@ -0,0 +1,71 @@
+# ToDo Demo APP
+
+Please read this great post about the todo list demo app, it was tested on k3s 1.17.2, eks 1.14 and rke 1.15:
+
+https://medium.com/better-programming/kubernetes-a-detailed-example-of-deployment-of-a-stateful-application-de3de33c8632
+
+You should understand how the secrets, configmaps and deployment manifests was built and what they do!
+
+Expand here to see the solution
+
+
+```
+k create -f db-credentials-secret.yaml
+```
+
+```
+k create -f db-root-credentials-secret.yaml
+```
+
+```
+k create -f mysql-configmap.yaml
+```
+
+```
+k create -f mysql-deployment.yaml
+```
+
+```
+k get all
+```
+
+```
+k get pvc
+```
+
+```
+k get pv
+```
+
+```
+k create -f backend-deployment.yaml
+```
+
+```
+k get pods
+```
+
+```
+k get svc
+```
+
+#### provide the external IP of the backend deployment service in the backend-configmap.yaml
+
+```
+vi backend-configmap.yaml
+```
+
+```
+k create -f backend-configmap.yaml
+```
+
+```
+k create -f frontend-deployment.yaml
+```
+
+```
+k get svc
+```
+
+
+
diff --git a/3-tier-app/backend-configmap.yaml b/3-tier-app/backend-configmap.yaml
new file mode 100644
index 00000000..2a7696e3
--- /dev/null
+++ b/3-tier-app/backend-configmap.yaml
@@ -0,0 +1,9 @@
+# ConfigMap to expose configuration related to backend application
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: backend-conf # name of configMap
+data:
+ server-uri: 192.168.64.24
+ # enternal ip of backend application 'Service'
+ # server-uri: to-do-app-backend.todoapp.svc.cluster.local # doesn't work, why?
diff --git a/3-tier-app/backend-deployment.yaml b/3-tier-app/backend-deployment.yaml
new file mode 100644
index 00000000..0ac570ff
--- /dev/null
+++ b/3-tier-app/backend-deployment.yaml
@@ -0,0 +1,61 @@
+# Define 'Service' to expose backend application deployment
+apiVersion: v1
+kind: Service
+metadata:
+ name: to-do-app-backend
+spec:
+ selector: # backend application pod lables should match these
+ app: to-do-app
+ tier: backend
+ ports:
+ - protocol: "TCP"
+ port: 80
+ targetPort: 8080
+ type: LoadBalancer # use NodePort, if you are not running Kubernetes on cloud
+---
+# Configure 'Deployment' of backend application
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: to-do-app-backend
+ labels:
+ app: to-do-app
+ tier: backend
+spec:
+ replicas: 2 # Number of replicas of back-end application to be deployed
+ selector:
+ matchLabels: # backend application pod labels should match these
+ app: to-do-app
+ tier: backend
+ template:
+ metadata:
+ labels: # Must macth 'Service' and 'Deployment' labels
+ app: to-do-app
+ tier: backend
+ spec:
+ containers:
+ - name: to-do-app-backend
+ image: kubernautslabs/to-do-app-backend # docker image of backend application
+ env: # Setting Enviornmental Variables
+ - name: DB_HOST # Setting Database host address from configMap
+ valueFrom:
+ configMapKeyRef:
+ name: db-conf # name of configMap
+ key: host
+ - name: DB_NAME # Setting Database name from configMap
+ valueFrom:
+ configMapKeyRef:
+ name: db-conf
+ key: name
+ - name: DB_USERNAME # Setting Database username from Secret
+ valueFrom:
+ secretKeyRef:
+ name: db-credentials # Secret Name
+ key: username
+ - name: DB_PASSWORD # Setting Database password from Secret
+ valueFrom:
+ secretKeyRef:
+ name: db-credentials
+ key: password
+ ports:
+ - containerPort: 8080
diff --git a/3-tier-app/db-credentials-secret.yaml b/3-tier-app/db-credentials-secret.yaml
new file mode 100644
index 00000000..185aca31
--- /dev/null
+++ b/3-tier-app/db-credentials-secret.yaml
@@ -0,0 +1,8 @@
+# Define 'Secret' to store db-credentials
+apiVersion: v1
+kind: Secret
+metadata:
+ name: db-credentials # Name of the 'Secret'
+data:
+ username: dXNlcg== # base64 encoded 'Secret' username
+ password: ZGV2ZWxvcA== # base64 encoded 'Secret' password
diff --git a/3-tier-app/db-root-credentials-secret.yaml b/3-tier-app/db-root-credentials-secret.yaml
new file mode 100644
index 00000000..bed622fc
--- /dev/null
+++ b/3-tier-app/db-root-credentials-secret.yaml
@@ -0,0 +1,8 @@
+# Define 'Secret' to store 'root' user Credentials
+apiVersion: v1
+kind: Secret
+metadata:
+ name: db-root-credentials # Name of the Secret
+data:
+ password: bWFnaWM= # base64 encoded 'root' password
+
diff --git a/3-tier-app/frontend-deployment.yaml b/3-tier-app/frontend-deployment.yaml
new file mode 100644
index 00000000..8f6067f0
--- /dev/null
+++ b/3-tier-app/frontend-deployment.yaml
@@ -0,0 +1,46 @@
+# Define 'Service' to expose FrontEnd Application
+apiVersion: v1
+kind: Service
+metadata:
+ name: to-do-app-frontend
+spec:
+ selector: # pod labels should match these
+ app: to-do-app
+ tier: frontend
+ ports:
+ - protocol: "TCP"
+ port: 80
+ targetPort: 8080
+ type: LoadBalancer # use NodePort if you are not running Kubernetes on Cloud
+---
+# 'Deployment' to manage of configuration of frontEnd Deployment
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: to-do-app-frontend
+ labels: # pod labels should match these
+ app: to-do-app
+ tier: frontend
+spec:
+ replicas: 2 # number of replicas of frontEnd application
+ selector:
+ matchLabels:
+ app: to-do-app
+ tier: frontend
+ template:
+ metadata:
+ labels: # Must match 'Service' and 'Deployment' labels
+ app: to-do-app
+ tier: frontend
+ spec:
+ containers:
+ - name: to-do-app-frontend
+ image: kubernautslabs/to-do-app-frontend # docker image of frontend application
+ env: # Setting Environmental Variables
+ - name: SERVER_URI # Setting Backend URI from configMap
+ valueFrom:
+ configMapKeyRef:
+ name: backend-conf # Name of configMap
+ key: server-uri
+ ports:
+ - containerPort: 8080
diff --git a/3-tier-app/mysql-configmap.yaml b/3-tier-app/mysql-configmap.yaml
new file mode 100644
index 00000000..3d59013f
--- /dev/null
+++ b/3-tier-app/mysql-configmap.yaml
@@ -0,0 +1,8 @@
+# Define 'Configmap' to store non-sensitive database configuration
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: db-conf # name of ConfigMap, referenced in other files
+data:
+ host: mysql # host address of mysql server, we are using DNS of Service
+ name: to-do-app-db # name of the database for application
diff --git a/3-tier-app/mysql-deployment.yaml b/3-tier-app/mysql-deployment.yaml
new file mode 100644
index 00000000..8f2d000b
--- /dev/null
+++ b/3-tier-app/mysql-deployment.yaml
@@ -0,0 +1,90 @@
+
+# Define a 'Service' To Expose mysql to Other Services
+apiVersion: v1
+kind: Service
+metadata:
+ name: mysql # DNS name
+ labels:
+ app: mysql
+ tier: database
+spec:
+ ports:
+ - port: 3306
+ targetPort: 3306
+ selector: # mysql Pod Should contain same labels
+ app: mysql
+ tier: database
+ clusterIP: None # We Use DNS, Thus ClusterIP is not relevant
+---
+# Define a 'Persistent Voulume Claim'(PVC) for Mysql Storage, dynamically provisioned by cluster
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: mysql-pv-claim # name of PVC essential for identifying the storage data
+ labels:
+ app: mysql
+ tier: database
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+---
+# Configure 'Deployment' of mysql server
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: mysql
+ labels:
+ app: mysql
+ tier: database
+spec:
+ selector: # mysql Pod Should contain same labels
+ matchLabels:
+ app: mysql
+ tier: database
+ strategy:
+ type: Recreate
+ template:
+ metadata:
+ labels: # Must match 'Service' and 'Deployment' selectors
+ app: mysql
+ tier: database
+ spec:
+ containers:
+ - image: mysql:5.7 # image from docker-hub
+ args:
+ - "--ignore-db-dir=lost+found" # Workaround for https://github.com/docker-library/mysql/issues/186
+ name: mysql
+ env:
+ - name: MYSQL_ROOT_PASSWORD # Setting Root Password of mysql From a 'Secret'
+ valueFrom:
+ secretKeyRef:
+ name: db-root-credentials # Name of the 'Secret'
+ key: password # 'key' inside the Secret which contains required 'value'
+ - name: MYSQL_USER # Setting USER username on mysql From a 'Secret'
+ valueFrom:
+ secretKeyRef:
+ name: db-credentials
+ key: username
+ - name: MYSQL_PASSWORD # Setting USER Password on mysql From a 'Secret'
+ valueFrom:
+ secretKeyRef:
+ name: db-credentials
+ key: password
+ - name: MYSQL_DATABASE # Setting Database Name from a 'ConfigMap'
+ valueFrom:
+ configMapKeyRef:
+ name: db-conf
+ key: name
+ ports:
+ - containerPort: 3306
+ name: mysql
+ volumeMounts: # Mounting voulume obtained from Persistent Volume Claim
+ - name: mysql-persistent-storage
+ mountPath: /var/lib/mysql
+ volumes:
+ - name: mysql-persistent-storage # Obtaining 'vloume' from PVC
+ persistentVolumeClaim:
+ claimName: mysql-pv-claim
diff --git a/3-tier-app/mysql-statefulset.yaml b/3-tier-app/mysql-statefulset.yaml
new file mode 100644
index 00000000..8cbf1238
--- /dev/null
+++ b/3-tier-app/mysql-statefulset.yaml
@@ -0,0 +1,89 @@
+
+# Define a 'Service' To Expose mysql to Other Services
+apiVersion: v1
+kind: Service
+metadata:
+ name: mysql # DNS name
+ labels:
+ app: mysql
+ tier: database
+spec:
+ ports:
+ - port: 3306
+ targetPort: 3306
+ selector: # mysql Pod Should contain same labels
+ app: mysql
+ tier: database
+ clusterIP: None # We Use DNS, Thus ClusterIP is not relevant
+---
+# Define a 'Persistent Voulume Claim'(PVC) for Mysql Storage, dynamically provisioned by cluster
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: mysql-pv-claim # name of PVC essential for identifying the storage data
+ labels:
+ app: mysql
+ tier: database
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+---
+# Configure 'Deployment' of mysql server
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: mysql
+ labels:
+ app: mysql
+ tier: database
+spec:
+ selector: # mysql Pod Should contain same labels
+ matchLabels:
+ app: mysql
+ tier: database
+ serviceName: mysql
+ template:
+ metadata:
+ labels: # Must match 'Service' and 'Deployment' selectors
+ app: mysql
+ tier: database
+ spec:
+ containers:
+ - image: mysql:5.7 # image from docker-hub
+ args:
+ - "--ignore-db-dir=lost+found" # Workaround for https://github.com/docker-library/mysql/issues/186
+ name: mysql
+ env:
+ - name: MYSQL_ROOT_PASSWORD # Setting Root Password of mysql From a 'Secret'
+ valueFrom:
+ secretKeyRef:
+ name: db-root-credentials # Name of the 'Secret'
+ key: password # 'key' inside the Secret which contains required 'value'
+ - name: MYSQL_USER # Setting USER username on mysql From a 'Secret'
+ valueFrom:
+ secretKeyRef:
+ name: db-credentials
+ key: username
+ - name: MYSQL_PASSWORD # Setting USER Password on mysql From a 'Secret'
+ valueFrom:
+ secretKeyRef:
+ name: db-credentials
+ key: password
+ - name: MYSQL_DATABASE # Setting Database Name from a 'ConfigMap'
+ valueFrom:
+ configMapKeyRef:
+ name: db-conf
+ key: name
+ ports:
+ - containerPort: 3306
+ name: mysql
+ volumeMounts: # Mounting voulume obtained from Persistent Volume Claim
+ - name: mysql-persistent-storage
+ mountPath: /var/lib/mysql
+ volumes:
+ - name: mysql-persistent-storage # Obtaining 'vloume' from PVC
+ persistentVolumeClaim:
+ claimName: mysql-pv-claim
diff --git a/4-node-red-all.yaml b/4-node-red-all.yaml
new file mode 100644
index 00000000..993c52d3
--- /dev/null
+++ b/4-node-red-all.yaml
@@ -0,0 +1,74 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: node-red
+ labels:
+ app: node-red
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: node-red
+ template:
+ metadata:
+ labels:
+ app: node-red
+ spec:
+ containers:
+ - name: node-red
+ image: insightful/node-red:slim
+ imagePullPolicy: Always
+ env:
+ - name: PUID
+ value: "1000"
+ - name: PGID
+ value: "1000"
+ ports:
+ - containerPort: 1880
+ volumeMounts:
+ - mountPath: /data
+ name: data-volume
+ volumes:
+ - name: data-volume
+ hostPath:
+ path: /srv/state/node-red
+ type: Directory
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: node-red
+spec:
+ selector:
+ app: node-red
+ ports:
+ - protocol: TCP
+ port: 8080
+ targetPort: 1880
+---
+# apiVersion: extensions/v1beta1
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: master.lan
+ annotations:
+ #kubernetes.io/ingress.class: nginx
+ ingressclass.kubernetes.io/is-default-class: "true" #changed
+spec:
+ ingressClassName: nginx
+ rules:
+ - host: master.lan
+ http:
+ paths:
+ - path: /
+ pathType: Prefix #changed
+ backend:
+ #changed
+ # serviceName: node-red
+ # servicePort: 8080
+ service:
+ name: node-red
+ port:
+ number: 8080
+
diff --git a/5-badpod.yaml b/5-badpod.yaml
new file mode 100644
index 00000000..996ea1aa
--- /dev/null
+++ b/5-badpod.yaml
@@ -0,0 +1,21 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: badpod
+spec:
+ containers:
+ - name: sise
+ image: mhausenblas/simpleservice:0.5.0
+ ports:
+ - containerPort: 9876
+ env:
+ - name: HEALTH_MIN
+ value: "1000"
+ - name: HEALTH_MAX
+ value: "4000"
+ livenessProbe:
+ initialDelaySeconds: 2
+ periodSeconds: 5
+ httpGet:
+ path: /health
+ port: 9876
diff --git a/5-health-check.yaml b/5-health-check.yaml
new file mode 100644
index 00000000..e073ed9e
--- /dev/null
+++ b/5-health-check.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: hc
+spec:
+ containers:
+ - name: sise
+ image: mhausenblas/simpleservice:0.5.0
+ ports:
+ - containerPort: 9876
+ livenessProbe:
+ initialDelaySeconds: 2
+ periodSeconds: 5
+ httpGet:
+ path: /health
+ port: 9876
diff --git a/5-liveness.yaml b/5-liveness.yaml
new file mode 100644
index 00000000..a359c64e
--- /dev/null
+++ b/5-liveness.yaml
@@ -0,0 +1,21 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ labels:
+ test: liveness
+ name: liveness
+spec:
+ containers:
+ - name: liveness
+ image: k8s.gcr.io/busybox
+ args:
+ - /bin/sh
+ - -c
+ - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 120
+ livenessProbe:
+ exec:
+ command:
+ - cat
+ - /tmp/healthy
+ initialDelaySeconds: 5
+ periodSeconds: 5
diff --git a/5-readiness.yaml b/5-readiness.yaml
new file mode 100644
index 00000000..b00b977c
--- /dev/null
+++ b/5-readiness.yaml
@@ -0,0 +1,21 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ labels:
+ test: readiness
+ name: readiness
+spec:
+ containers:
+ - name: readiness
+ image: k8s.gcr.io/busybox
+ args:
+ - /bin/sh
+ - -c
+ - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 120
+ readinessProbe:
+ exec:
+ command:
+ - cat
+ - /tmp/healthy
+ initialDelaySeconds: 3
+ periodSeconds: 3
diff --git a/CronJob/README.md b/CronJob/README.md
new file mode 100644
index 00000000..7da8e917
--- /dev/null
+++ b/CronJob/README.md
@@ -0,0 +1,279 @@
+Table of Contents
+=================
+
+- [Table of Contents](#table-of-contents)
+- [CronJob](#cronjob)
+- [Cron schedule syntax](#cron-schedule-syntax)
+- [Time zones](#time-zones)
+- [CronJob limitations](#cronjob-limitations)
+ - [For example](#for-example)
+- [Running Automated Tasks with a CronJob](#running-automated-tasks-with-a-cronjob)
+ - [Deleting a CronJob](#deleting-a-cronjob)
+ - [Writing a CronJob Spec](#writing-a-cronjob-spec)
+ - [Schedule](#schedule)
+ - [Job Template](#job-template)
+ - [Starting Deadline](#starting-deadline)
+ - [Concurrency Policy](#concurrency-policy)
+ - [Suspend](#suspend)
+ - [Jobs History Limits](#jobs-history-limits)
+- [Reference links](#reference-links)
+
+
+# CronJob
+
+A CronJob creates Jobs on a repeating schedule.
+
+One CronJob object is like one line of a crontab (cron table) file. It runs a job periodically on a given schedule, written in Cron format.
+
+CronJobs are meant for performing regular scheduled actions such as backups, report generation, and so on. Each of those tasks should be configured to recur indefinitely (for example: once a day / week / month); you can define the point in time within that interval when the job should start.
+
+Example
+This example CronJob manifest prints the current time and a hello message every minute:
+
+
+```yaml
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: hello
+spec:
+ schedule: "* * * * *"
+ jobTemplate:
+ spec:
+ template:
+ spec:
+ containers:
+ - name: hello
+ image: busybox:1.28
+ imagePullPolicy: IfNotPresent
+ command:
+ - /bin/sh
+ - -c
+ - date; echo Hello from the Kubernetes cluster
+ restartPolicy: OnFailure
+```
+
+# Cron schedule syntax
+
+```
+# ┌───────────── minute (0 - 59)
+# │ ┌───────────── hour (0 - 23)
+# │ │ ┌───────────── day of the month (1 - 31)
+# │ │ │ ┌───────────── month (1 - 12)
+# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday;
+# │ │ │ │ │ 7 is also Sunday on some systems)
+# │ │ │ │ │ OR sun, mon, tue, wed, thu, fri, sat
+# │ │ │ │ │
+# * * * * *
+```
+
+|Entry| Description| Equivalent to|
+|---|---|---|
+|@yearly (or @annually)| Run once a year at midnight of 1 January| 0 0 1 1 *|
+|@monthly| Run once a month at midnight of the first day of the month| 0 0 1 * *|
+|@weekly| Run once a week at midnight on Sunday morning| 0 0 * * 0|
+@daily (or @midnight)| Run once a day at midnight| 0 0 * * *|
+@hourly| Run once an hour at the beginning of the hour| 0 * * * *|
+
+For example, the line below states that the task must be started every Friday at midnight, as well as on the 13th of each month at midnight:
+
+`0 0 13 * 5`
+
+To generate CronJob schedule expressions, you can also use web tools like [crontab.guru](https://crontab.guru/).
+
+# Time zones
+
+For CronJobs with no time zone specified, the kube-controller-manager interprets schedules relative to its local time zone.
+
+# CronJob limitations
+
+A cron job creates a job object _about_ once per execution time of its schedule. We say "about" because there are certain circumstances where two jobs might be created, or no job might be created. We attempt to make these rare, but do not completely prevent them. Therefore, jobs should be _idempotent_.
+
+If `startingDeadlineSeconds` is set to a large value or left unset (the default) and if `concurrencyPolicy` is set to `Allow`, the jobs will always run at least once.
+
+For every CronJob, the CronJob Controller checks how many schedules it missed in the duration from its last scheduled time until now. If there are more than 100 missed schedules, then it does not start the job and logs the error
+
+`Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.`
+
+It is important to note that if the `startingDeadlineSeconds` field is set (not `nil`), the controller counts how many missed jobs occurred from the value of `startingDeadlineSeconds` until now rather than from the last scheduled time until now. For example, if `startingDeadlineSeconds` is `200`, the controller counts how many missed jobs occurred in the last 200 seconds.
+
+A CronJob is counted as missed if it has failed to be created at its scheduled time. For example, If `concurrencyPolicy` is set to `Forbid` and a CronJob was attempted to be scheduled when there was a previous schedule still running, then it would count as missed.
+
+### For example
+
+Suppose a CronJob is set to schedule a new Job every one minute beginning at `08:30:00`, and its `startingDeadlineSeconds` field is not set.
+
+If the CronJob controller happens to be down from `08:29:00` to `10:21:00`, the job will not start as the number of missed jobs which missed their schedule is greater than 100.
+
+To illustrate this concept further, suppose a CronJob is set to schedule a new Job every one minute beginning at `08:30:00`, and its `startingDeadlineSeconds` is set to 200 seconds. If the CronJob controller happens to be down for the same period as the previous example (`08:29:00` to `10:21:00`,) the Job will still start at 10:22:00.
+
+This happens as the controller now checks how many missed schedules happened in the last 200 seconds (ie, 3 missed schedules), rather than from the last scheduled time until now.
+
+The CronJob is only responsible for creating Jobs that match its schedule, and the Job in turn is responsible for the management of the Pods it represents.
+
+
+# Running Automated Tasks with a CronJob
+
+Cron jobs require a config file. Here is a manifest for a CronJob that runs a simple demonstration task every minute:
+
+```yaml
+#cronjob.yaml
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: hello
+spec:
+ schedule: "* * * * *"
+ jobTemplate:
+ spec:
+ template:
+ spec:
+ containers:
+ - name: hello
+ image: busybox:1.28
+ imagePullPolicy: IfNotPresent
+ command:
+ - /bin/sh
+ - -c
+ - date; echo Hello from the Kubernetes cluster
+ restartPolicy: OnFailure
+```
+
+
+Run the example CronJob by using this command:
+
+```shell
+kubectl create -f cronjob.yaml
+```
+
+The output is similar to this:
+
+```
+cronjob.batch/hello created
+```
+
+After creating the cron job, get its status using this command:
+
+```shell
+kubectl get cronjob hello
+```
+
+The output is similar to this:
+
+```
+NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
+hello */1 * * * * False 0 10s
+```
+
+As you can see from the results of the command, the cron job has not scheduled or run any jobs yet. Watch for the job to be created in around one minute:
+
+```shell
+kubectl get jobs --watch
+```
+
+The output is similar to this:
+
+```
+NAME COMPLETIONS DURATION AGE
+hello-4111706356 0/1 0s
+hello-4111706356 0/1 0s 0s
+hello-4111706356 1/1 5s 5s
+```
+
+Now you've seen one running job scheduled by the "hello" cron job. You can stop watching the job and view the cron job again to see that it scheduled the job:
+
+```shell
+kubectl get cronjob hello
+```
+
+The output is similar to this:
+
+```
+NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
+hello */1 * * * * False 0 50s 75s
+```
+
+You should see that the cron job `hello` successfully scheduled a job at the time specified in `LAST SCHEDULE`. There are currently 0 active jobs, meaning that the job has completed or failed.
+
+Now, find the pods that the last scheduled job created and view the standard output of one of the pods.
+
+**Note:** The job name is different from the pod name.
+
+```shell
+# Replace "hello-4111706356" with the job name in your system
+pods=$(kubectl get pods --selector=job-name=hello-4111706356 --output=jsonpath={.items[*].metadata.name})
+```
+
+Show the pod log:
+
+```shell
+kubectl logs $pods
+```
+
+
+## Deleting a CronJob
+
+When you don't need a cron job any more, delete it with `kubectl delete cronjob `:
+
+```shell
+kubectl delete cronjob hello
+```
+
+Deleting the cron job removes all the jobs and pods it created and stops it from creating additional jobs.
+
+## Writing a CronJob Spec
+
+As with all other Kubernetes objects, a CronJob must have `apiVersion`, `kind`, and `metadata` fields.
+
+Each manifest for a CronJob also needs a `.spec` section.
+
+### Schedule
+
+The `.spec.schedule` is a required field of the `.spec`. It takes a Cron format string, such as `0 * * * *` or `@hourly`, as schedule time of its jobs to be created and executed.
+
+### Job Template
+
+The `.spec.jobTemplate` is the template for the job, and it is required. It has exactly the same schema as a Job, except that it is nested and does not have an `apiVersion` or `kind`. For information about writing a job `.spec`.
+
+### Starting Deadline
+
+The `.spec.startingDeadlineSeconds` field is optional.
+
+It stands for the deadline in seconds for starting the job if it misses its scheduled time for any reason.
+
+After the deadline, the cron job does not start the job. Jobs that do not meet their deadline in this way count as failed jobs. If this field is not specified, the jobs have no deadline.
+
+If the `.spec.startingDeadlineSeconds` field is set (not null), the CronJob controller measures the time between when a job is expected to be created and now. If the difference is higher than that limit, it will skip this execution.
+
+For example, if it is set to `200`, it allows a job to be created for up to 200 seconds after the actual schedule.
+
+### Concurrency Policy
+
+The `.spec.concurrencyPolicy` field is also optional. It specifies how to treat concurrent executions of a job that is created by this cron job. The spec may specify only one of the following concurrency policies:
+
+- `Allow` (default): The cron job allows concurrently running jobs
+- `Forbid`: The cron job does not allow concurrent runs; if it is time for a new job run and the previous job run hasn't finished yet, the cron job skips the new job run
+- `Replace`: If it is time for a new job run and the previous job run hasn't finished yet, the cron job replaces the currently running job run with a new job run
+
+Note that concurrency policy only applies to the jobs created by the same cron job. If there are multiple cron jobs, their respective jobs are always allowed to run concurrently.
+
+### Suspend
+
+The `.spec.suspend` field is also optional. If it is set to `true`, all subsequent executions are suspended. This setting does not apply to already started executions. Defaults to false.
+
+### Jobs History Limits
+
+The `.spec.successfulJobsHistoryLimit` and `.spec.failedJobsHistoryLimit` fields are optional.
+
+These fields specify how many completed and failed jobs should be kept. By default, they are set to 3 and 1 respectively.
+
+Setting a limit to `0` corresponds to keeping none of the corresponding kind of jobs after they finish.
+
+
+# Reference links
+
+- [CronJobs concepts](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/)
+- [Automated Tasks with a CronJob](https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/)
+
+
+
diff --git a/CronJob/cronjob.yaml b/CronJob/cronjob.yaml
new file mode 100644
index 00000000..a89278f8
--- /dev/null
+++ b/CronJob/cronjob.yaml
@@ -0,0 +1,19 @@
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: hello
+spec:
+ schedule: "* * * * *"
+ jobTemplate:
+ spec:
+ template:
+ spec:
+ containers:
+ - name: hello
+ image: busybox:1.28
+ imagePullPolicy: IfNotPresent
+ command:
+ - /bin/sh
+ - -c
+ - date; echo Hello from the Kubernetes cluster
+ restartPolicy: OnFailure
\ No newline at end of file
diff --git a/DaemonSets/README.md b/DaemonSets/README.md
new file mode 100644
index 00000000..ff9f12d9
--- /dev/null
+++ b/DaemonSets/README.md
@@ -0,0 +1,43 @@
+A _DaemonSet_ ensures that all (or some) Nodes run a copy of a Pod.
+
+As nodes are added to the cluster, Pods are added to them.
+
+As nodes are removed from the cluster, those Pods are garbage collected. Deleting a DaemonSet will clean up the Pods it created.
+
+Some typical uses of a DaemonSet are:
+
+- running a cluster storage daemon on every node
+- running a logs collection daemon on every node
+- running a node monitoring daemon on every node
+
+
+## Create a daemonset:
+
+```
+kubectl create -f daemonset.yaml
+```
+
+## Check the pod running:
+
+```
+kubectl get pods -n kube-system
+```
+
+## List out the daemonsets
+
+```
+kubectl get ds -o wide
+```
+
+## Edit a daemonset:
+
+```
+kubectl edit daemonset fluentd
+```
+## Delete a daemonset:
+
+```
+kubectl delete daemonset fluentd
+```
+
+### Reference link : https://medium.com/avmconsulting-blog/deploying-daemonsets-service-in-kubernetes-k8s-37d642dcd66f
\ No newline at end of file
diff --git a/DaemonSets/daemonset.yaml b/DaemonSets/daemonset.yaml
new file mode 100644
index 00000000..1070ce6f
--- /dev/null
+++ b/DaemonSets/daemonset.yaml
@@ -0,0 +1,19 @@
+apiVersion: apps/v1
+kind: DaemonSet
+metadata:
+ name: fluentd
+ namespace: kube-system
+ labels:
+ k8s-app: fluentd
+spec:
+ selector:
+ matchLabels:
+ name: fluentd
+ template:
+ metadata:
+ labels:
+ name: fluentd
+ spec:
+ containers:
+ - name: fluentd
+ image: fluentd:latest
\ No newline at end of file
diff --git a/Helm/README.md b/Helm/README.md
new file mode 100644
index 00000000..a6d31bff
--- /dev/null
+++ b/Helm/README.md
@@ -0,0 +1,245 @@
+Table of Contents
+=================
+
+- [Table of Contents](#table-of-contents)
+- [What is Helm?](#what-is-helm)
+ - [Manage Complexity](#manage-complexity)
+ - [Easy Updates](#easy-updates)
+ - [Simple Sharing](#simple-sharing)
+ - [Rollbacks](#rollbacks)
+- [Helm Architecture](#helm-architecture)
+ - [The Purpose of Helm](#the-purpose-of-helm)
+ - [Components](#components)
+ - [Implementation](#implementation)
+- [Installing Helm](#installing-helm)
+ - [From The Helm Project](#from-the-helm-project)
+ - [From the Binary Releases](#from-the-binary-releases)
+ - [From Script](#from-script)
+ - [Through Package Managers](#through-package-managers)
+ - [From Homebrew (macOS)](#from-homebrew-macos)
+ - [Initialize a Helm Chart Repository](#initialize-a-helm-chart-repository)
+ - [Install an Example Chart](#install-an-example-chart)
+ - [Learn About Releases](#learn-about-releases)
+ - [Uninstall a Release](#uninstall-a-release)
+ - [Reading the Help Text](#reading-the-help-text)
+ - [helm version](#helm-version)
+
+# What is Helm?
+
+Helm helps you manage Kubernetes applications — Helm Charts help you define, install, and upgrade even the most complex Kubernetes application.
+
+Charts are easy to create, version, share, and publish.
+
+### Manage Complexity
+
+Charts describe even the most complex apps, provide repeatable application installation, and serve as a single point of authority.
+
+### Easy Updates
+
+Take the pain out of updates with in-place upgrades and custom hooks.
+
+### Simple Sharing
+
+Charts are easy to version, share, and host on public or private servers.
+
+### Rollbacks
+
+Use `helm rollback` to roll back to an older version of a release with ease.
+
+
+# Helm Architecture
+
+This describes the Helm architecture at a high level.
+
+## The Purpose of Helm
+
+Helm is a tool for managing Kubernetes packages called _charts_. Helm can do the following:
+
+- Create new charts from scratch
+- Package charts into chart archive (tgz) files
+- Interact with chart repositories where charts are stored
+- Install and uninstall charts into an existing Kubernetes cluster
+- Manage the release cycle of charts that have been installed with Helm
+
+For Helm, there are three important concepts:
+
+1. The _chart_ is a bundle of information necessary to create an instance of a Kubernetes application.
+2. The _config_ contains configuration information that can be merged into a packaged chart to create a releasable object.
+3. A _release_ is a running instance of a _chart_, combined with a specific _config_.
+
+## Components
+
+Helm is an executable which is implemented into two distinct parts:
+
+**The Helm Client** is a command-line client for end users. The client is responsible for the following:
+
+- Local chart development
+- Managing repositories
+- Managing releases
+- Interfacing with the Helm library
+ - Sending charts to be installed
+ - Requesting upgrading or uninstalling of existing releases
+
+**The Helm Library** provides the logic for executing all Helm operations. It interfaces with the Kubernetes API server and provides the following capability:
+
+- Combining a chart and configuration to build a release
+- Installing charts into Kubernetes, and providing the subsequent release object
+- Upgrading and uninstalling charts by interacting with Kubernetes
+
+The standalone Helm library encapsulates the Helm logic so that it can be leveraged by different clients.
+
+## Implementation
+
+The Helm client and library is written in the Go programming language.
+
+The library uses the Kubernetes client library to communicate with Kubernetes. Currently, that library uses REST+JSON. It stores information in Secrets located inside of Kubernetes. It does not need its own database.
+
+Configuration files are, when possible, written in YAML.
+
+# Installing Helm
+
+This guide shows how to install the Helm CLI. Helm can be installed either from source, or from pre-built binary releases.
+
+## From The Helm Project
+
+The Helm project provides two ways to fetch and install Helm. These are the official methods to get Helm releases.
+
+In addition to that, the Helm community provides methods to install Helm through different package managers. Installation through those methods can be found below the official methods.
+
+### From the Binary Releases
+
+Every [release](https://github.com/helm/helm/releases) of Helm provides binary releases for a variety of OSes. These binary versions can be manually downloaded and installed.
+
+1. Download your [desired version](https://github.com/helm/helm/releases)
+2. Unpack it
+
+```
+tar -zxvf helm-v3.0.0-linux-amd64.tar.gz
+```
+
+3. Find the `helm` binary in the unpacked directory, and move it to its desired destination
+
+```
+mv linux-amd64/helm /usr/local/bin/helm
+```
+
+From there, you should be able to run the client and [add the stable repo](https://helm.sh/docs/intro/quickstart/#initialize-a-helm-chart-repository):
+
+```
+helm repo add name chart repo
+```
+
+Example:
+
+```
+helm repo add bitnami https://charts.bitnami.com/bitnami
+```
+
+
+### From Script
+
+Helm now has an installer script that will automatically grab the latest version of Helm and [install it locally](https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3).
+
+You can fetch that script, and then execute it locally. It's well documented so that you can read through it and understand what it is doing before you run it.
+
+```console
+curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
+
+chmod 700 get_helm.sh
+
+./get_helm.sh
+```
+
+## Through Package Managers
+
+The Helm community provides the ability to install Helm through operating system package managers. These are not supported by the Helm project and are not considered trusted 3rd parties.
+
+### From Homebrew (macOS)
+
+Members of the Helm community have contributed a Helm formula build to Homebrew. This formula is generally up to date.
+
+```console
+brew install helm
+```
+
+## Initialize a Helm Chart Repository
+
+Once you have Helm ready, you can add a chart repository. Check [Artifact Hub](https://artifacthub.io/packages/search?kind=0) for available Helm chart repositories.
+
+```console
+helm repo add bitnami https://charts.bitnami.com/bitnami
+```
+
+Once this is installed, you will be able to list the charts you can install:
+
+```console
+helm search repo bitnami
+```
+
+## Install an Example Chart
+
+To install a chart, you can run the `helm install` command. Helm has several ways to find and install a chart, but the easiest is to use the `bitnami` charts.
+
+```console
+helm repo update # Make sure we get the latest list of charts
+```
+
+```
+helm install bitnami/mysql --generate-name
+```
+
+In the example above, the `bitnami/mysql` chart was released, and the name of our new release is `mysql-1612624192`.
+
+You get a simple idea of the features of this MySQL chart by running `helm show chart bitnami/mysql`.
+
+Or you could run `helm show all bitnami/mysql` to get all information about the chart.
+
+Whenever you install a chart, a new release is created. So one chart can be installed multiple times into the same cluster. And each can be independently managed and upgraded.
+
+## Learn About Releases
+
+It's easy to see what has been released using Helm:
+
+```console
+helm list
+```
+
+The `helm list` (or `helm ls`) function will show you a list of all deployed releases.
+
+## Uninstall a Release
+
+To uninstall a release, use the `helm uninstall` command:
+
+```console
+helm uninstall mysql
+```
+
+This will uninstall `mysql` from Kubernetes, which will remove all resources associated with the release as well as the release history.
+
+If the flag `--keep-history` is provided, release history will be kept. You will be able to request information about that release:
+
+```console
+helm status mysql
+```
+
+Because Helm tracks your releases even after you've uninstalled them, you can audit a cluster's history, and even undelete a release (with `helm rollback`).
+
+## Reading the Help Text
+
+To learn more about the available Helm commands, use `helm help` or type a command followed by the `-h` flag:
+
+```console
+$ helm get -h
+```
+
+## helm version
+
+Show the version for Helm.
+
+This will print a representation the version of Helm.
+
+```
+helm version
+```
+
+print the client version information
\ No newline at end of file
diff --git a/Istio-Samples/README.md b/Istio-Samples/README.md
new file mode 100644
index 00000000..070f67af
--- /dev/null
+++ b/Istio-Samples/README.md
@@ -0,0 +1,19 @@
+# Istio Samples
+
+
+This directory contains sample applications highlighting various Istio features.
+
+A variety of fully working example uses for Istio that you can experiment with.
+
+
+Bookinfo Application:
+
+Deploys a sample application composed of four separate microservices used to demonstrate various Istio features.
+
+Bookinfo with a Virtual Machine:
+
+Run the Bookinfo application with a MySQL service running on a virtual machine within your mesh.
+
+Learn Microservices using Kubernetes and Istio:
+
+This modular tutorial provides new users with hands-on experience using Istio for common microservices scenarios, one step at a time.
\ No newline at end of file
diff --git a/Istio-Samples/addons/README.md b/Istio-Samples/addons/README.md
new file mode 100644
index 00000000..6259c014
--- /dev/null
+++ b/Istio-Samples/addons/README.md
@@ -0,0 +1,102 @@
+# Telemetry Addons
+
+This directory contains sample deployments of various addons that integrate with Istio. While these applications
+are not a part of Istio, they are essential to making the most of Istio's observability features.
+
+The deployments here are meant to quickly get up and running, and are optimized for this case. As a result,
+they may not be suitable for production. See below for more info on integrating a production grade version of each
+addon.
+
+## Getting started
+
+To quickly deploy all addons:
+
+```shell script
+kubectl apply -f samples/addons
+```
+
+Alternatively, you can deploy individual addons:
+
+```shell script
+kubectl apply -f samples/addons/prometheus.yaml
+```
+
+## Addons
+
+### Prometheus
+
+[Prometheus](https://prometheus.io/) is an open source monitoring system and time series database.
+You can use Prometheus with Istio to record metrics that track the health of Istio and of applications within the service mesh.
+You can visualize metrics using tools like [Grafana](#grafana) and [Kiali](#kiali).
+
+For more information about integrating with Prometheus, please see the [Prometheus integration page](https://istio.io/docs/ops/integrations/prometheus/).
+
+### Grafana
+
+[Grafana](http://grafana.com/) is an open source monitoring solution that can be used to configure dashboards for Istio.
+You can use Grafana to monitor the health of Istio and of applications within the service mesh.
+
+This sample provides the following dashboards:
+
+* [Mesh Dashboard](https://grafana.com/grafana/dashboards/7639) provides an overview of all services in the mesh.
+* [Service Dashboard](https://grafana.com/grafana/dashboards/7636) provides a detailed breakdown of metrics for a service.
+* [Workload Dashboard](https://grafana.com/grafana/dashboards/7630) provides a detailed breakdown of metrics for a workload.
+* [Performance Dashboard](https://grafana.com/grafana/dashboards/11829) monitors the resource usage of the mesh.
+* [Control Plane Dashboard](https://grafana.com/grafana/dashboards/7645) monitors the health and performance of the control plane.
+* [WASM Extension Dashboard](https://grafana.com/grafana/dashboards/13277) provides an overview of mesh wide WebAssembly extension runtime and loading state.
+
+For more information about integrating with Grafana, please see the [Grafana integration page](https://istio.io/docs/ops/integrations/grafana/).
+
+### Kiali
+
+[Kiali](https://kiali.io/) is an observability console for Istio with service mesh configuration capabilities.
+It helps you to understand the structure of your service mesh by inferring the topology, and also provides the health of your mesh.
+Kiali provides detailed metrics, and a basic [Grafana](#grafana) integration is available for advanced queries.
+Distributed tracing is provided by integrating [Jaeger](#jaeger).
+
+For more information about using Kiali, see the [Visualizing Your Mesh](https://istio.io/docs/tasks/observability/kiali/) task.
+
+### Jaeger
+
+[Jaeger](https://www.jaegertracing.io/) is an open source end to end distributed tracing system, allowing users to monitor and troubleshoot transactions in complex distributed systems.
+
+Jaeger helps in a variety of tasks including:
+
+* Distributed context propagation
+* Distributed transaction monitoring
+* Root cause analysis
+* Service dependency analysis
+* Performance / latency optimization
+
+For more information about integrating with Jaeger, please see the [Jaeger integration page](https://istio.io/docs/tasks/observability/distributed-tracing/jaeger/).
+
+### Zipkin
+
+[Zipkin](https://zipkin.io/) is a distributed tracing system. It helps gather timing data needed to troubleshoot latency problems in service architectures. Features include both the collection and lookup of this data.
+
+Zipkin is an alternative to Jaeger and is not deployed by default. To replace Jaeger with Zipkin, run `kubectl apply -f samples/addons/extras/zipkin.yaml`.
+You may also want to remove the Jaeger deployment, which will not be used, with `kubectl delete deployment jaeger`, or avoid installing it
+to begin with by following the selective installation steps in [Getting Started](#getting-started).
+
+For more information about integrating with Zipkin, please see the [Zipkin integration page](https://istio.io/docs/tasks/observability/distributed-tracing/zipkin/).
+
+### Prometheus Operator
+
+The [Prometheus Operator](https://github.com/coreos/prometheus-operator) manages and operators a Prometheus instance.
+
+As an alternative to the standard Prometheus deployment, we provide a `ServiceMonitor` to monitor the Istio control plane and `PodMonitor`
+Envoy proxies. To use these, make sure you have the Prometheus operator deployed, then run `kubectl apply -f samples/addons/extras/prometheus-operator.yaml`.
+
+> **Note**
+>
+> The example `PodMonitor` requires [metrics merging](https://istio.io/latest/docs/ops/integrations/prometheus/#option-1-metrics-merging) to be enabled. This is enabled by default.
+>
+> **Note**
+>
+> The configurations here are only for Istio deployments, and do not scrape metrics from the Kubernetes components.
+> See the [Cluster Monitoring](https://coreos.com/operators/prometheus/docs/latest/user-guides/cluster-monitoring.html) documentation for configuring this.
+>
+> **Warning**
+>
+> When the example `PodMonitor` is used with OpenShift Monitoring, it must be created in all namespaces where istio-proxies exist.
+> This is because `namespaceSelector` is ignored for tenancy isolation.
diff --git a/Istio-Samples/addons/extras/prometheus-operator.yaml b/Istio-Samples/addons/extras/prometheus-operator.yaml
new file mode 100644
index 00000000..73a926ef
--- /dev/null
+++ b/Istio-Samples/addons/extras/prometheus-operator.yaml
@@ -0,0 +1,66 @@
+apiVersion: monitoring.coreos.com/v1
+kind: PodMonitor
+metadata:
+ name: envoy-stats-monitor
+ namespace: istio-system
+ labels:
+ monitoring: istio-proxies
+ release: istio
+spec:
+ selector:
+ matchExpressions:
+ - {key: istio-prometheus-ignore, operator: DoesNotExist}
+ namespaceSelector:
+ any: true
+ jobLabel: envoy-stats
+ podMetricsEndpoints:
+ - path: /stats/prometheus
+ interval: 15s
+ relabelings:
+ - action: keep
+ sourceLabels: [__meta_kubernetes_pod_container_name]
+ regex: "istio-proxy"
+ - action: keep
+ sourceLabels: [__meta_kubernetes_pod_annotationpresent_prometheus_io_scrape]
+ - action: replace
+ regex: (\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})
+ replacement: '[$2]:$1'
+ sourceLabels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_port
+ - __meta_kubernetes_pod_ip
+ targetLabel: __address__
+ - action: replace
+ regex: (\d+);((([0-9]+?)(\.|$)){4})
+ replacement: $2:$1
+ sourceLabels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_port
+ - __meta_kubernetes_pod_ip
+ targetLabel: __address__
+ - action: labeldrop
+ regex: "__meta_kubernetes_pod_label_(.+)"
+ - sourceLabels: [__meta_kubernetes_namespace]
+ action: replace
+ targetLabel: namespace
+ - sourceLabels: [__meta_kubernetes_pod_name]
+ action: replace
+ targetLabel: pod_name
+---
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: istio-component-monitor
+ namespace: istio-system
+ labels:
+ monitoring: istio-components
+ release: istio
+spec:
+ jobLabel: istio
+ targetLabels: [app]
+ selector:
+ matchExpressions:
+ - {key: istio, operator: In, values: [pilot]}
+ namespaceSelector:
+ any: true
+ endpoints:
+ - port: http-monitoring
+ interval: 15s
diff --git a/Istio-Samples/addons/extras/skywalking.yaml b/Istio-Samples/addons/extras/skywalking.yaml
new file mode 100644
index 00000000..0633b74d
--- /dev/null
+++ b/Istio-Samples/addons/extras/skywalking.yaml
@@ -0,0 +1,133 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: skywalking-oap
+ namespace: istio-system
+ labels:
+ app: skywalking-oap
+spec:
+ selector:
+ matchLabels:
+ app: skywalking-oap
+ template:
+ metadata:
+ labels:
+ app: skywalking-oap
+ sidecar.istio.io/inject: "false"
+ spec:
+ containers:
+ - name: skywalking-oap
+ image: apache/skywalking-oap-server:9.1.0
+ env:
+ - name: SW_HEALTH_CHECKER
+ value: default
+ readinessProbe:
+ exec:
+ command:
+ - /skywalking/bin/swctl
+ - health
+ initialDelaySeconds: 30
+ periodSeconds: 5
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: tracing
+ namespace: istio-system
+ labels:
+ app: skywalking-oap
+spec:
+ type: ClusterIP
+ ports:
+ - name: grpc
+ port: 11800
+ protocol: TCP
+ targetPort: 11800
+ - name: http-query
+ port: 12800
+ protocol: TCP
+ targetPort: 12800
+ selector:
+ app: skywalking-oap
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ name: skywalking-oap
+ name: skywalking-oap
+ namespace: istio-system
+spec:
+ ports:
+ - port: 11800
+ targetPort: 11800
+ name: grpc
+ - port: 12800
+ targetPort: 12800
+ name: http-query
+ selector:
+ app: skywalking-oap
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: skywalking-ui
+ namespace: istio-system
+ labels:
+ app: skywalking-ui
+spec:
+ selector:
+ matchLabels:
+ app: skywalking-ui
+ template:
+ metadata:
+ labels:
+ app: skywalking-ui
+ annotations:
+ sidecar.istio.io/inject: "false"
+ spec:
+ containers:
+ - name: skywalking-ui
+ image: apache/skywalking-ui:9.1.0
+ env:
+ - name: SW_OAP_ADDRESS
+ value: http://skywalking-oap:12800
+ readinessProbe:
+ httpGet:
+ path: /
+ port: 8080
+ initialDelaySeconds: 30
+ periodSeconds: 5
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: tracing-ui
+ namespace: istio-system
+ labels:
+ app: skywalking-ui
+spec:
+ type: ClusterIP
+ ports:
+ - name: http
+ port: 8080
+ protocol: TCP
+ targetPort: 8080
+ selector:
+ app: skywalking-ui
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ name: skywalking-ui
+ name: skywalking-ui
+ namespace: istio-system
+spec:
+ ports:
+ - port: 8080
+ targetPort: 8080
+ name: http
+ selector:
+ app: skywalking-ui
diff --git a/Istio-Samples/addons/extras/zipkin.yaml b/Istio-Samples/addons/extras/zipkin.yaml
new file mode 100644
index 00000000..b9bced3d
--- /dev/null
+++ b/Istio-Samples/addons/extras/zipkin.yaml
@@ -0,0 +1,61 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: zipkin
+ namespace: istio-system
+ labels:
+ app: zipkin
+spec:
+ selector:
+ matchLabels:
+ app: zipkin
+ template:
+ metadata:
+ labels:
+ app: zipkin
+ sidecar.istio.io/inject: "false"
+ spec:
+ containers:
+ - name: zipkin
+ image: openzipkin/zipkin-slim:2.23.14
+ env:
+ - name: STORAGE_METHOD
+ value: "mem"
+ readinessProbe:
+ httpGet:
+ path: /health
+ port: 9411
+ initialDelaySeconds: 5
+ periodSeconds: 5
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: tracing
+ namespace: istio-system
+ labels:
+ app: zipkin
+spec:
+ type: ClusterIP
+ ports:
+ - name: http-query
+ port: 80
+ protocol: TCP
+ targetPort: 9411
+ selector:
+ app: zipkin
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ name: zipkin
+ name: zipkin
+ namespace: istio-system
+spec:
+ ports:
+ - port: 9411
+ targetPort: 9411
+ name: http-query
+ selector:
+ app: zipkin
diff --git a/Istio-Samples/addons/grafana.yaml b/Istio-Samples/addons/grafana.yaml
new file mode 100644
index 00000000..eb2a9cdc
--- /dev/null
+++ b/Istio-Samples/addons/grafana.yaml
@@ -0,0 +1,1135 @@
+---
+# Source: grafana/templates/serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ labels:
+ helm.sh/chart: grafana-6.61.1
+ app.kubernetes.io/name: grafana
+ app.kubernetes.io/instance: grafana
+ app.kubernetes.io/version: "10.1.5"
+ app.kubernetes.io/managed-by: Helm
+ name: grafana
+ namespace: istio-system
+---
+# Source: grafana/templates/configmap.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: grafana
+ namespace: istio-system
+ labels:
+ helm.sh/chart: grafana-6.61.1
+ app.kubernetes.io/name: grafana
+ app.kubernetes.io/instance: grafana
+ app.kubernetes.io/version: "10.1.5"
+ app.kubernetes.io/managed-by: Helm
+data:
+ grafana.ini: |
+ [analytics]
+ check_for_updates = true
+ [grafana_net]
+ url = https://grafana.net
+ [log]
+ mode = console
+ [paths]
+ data = /var/lib/grafana/
+ logs = /var/log/grafana
+ plugins = /var/lib/grafana/plugins
+ provisioning = /etc/grafana/provisioning
+ [server]
+ domain = ''
+ datasources.yaml: |
+ apiVersion: 1
+ datasources:
+ - access: proxy
+ editable: true
+ isDefault: true
+ jsonData:
+ timeInterval: 5s
+ name: Prometheus
+ orgId: 1
+ type: prometheus
+ url: http://prometheus:9090
+ - access: proxy
+ editable: true
+ isDefault: false
+ jsonData:
+ timeInterval: 5s
+ name: Loki
+ orgId: 1
+ type: loki
+ url: http://loki:3100
+ dashboardproviders.yaml: |
+ apiVersion: 1
+ providers:
+ - disableDeletion: false
+ folder: istio
+ name: istio
+ options:
+ path: /var/lib/grafana/dashboards/istio
+ orgId: 1
+ type: file
+ - disableDeletion: false
+ folder: istio
+ name: istio-services
+ options:
+ path: /var/lib/grafana/dashboards/istio-services
+ orgId: 1
+ type: file
+---
+# Source: grafana/templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: grafana
+ namespace: istio-system
+ labels:
+ helm.sh/chart: grafana-6.61.1
+ app.kubernetes.io/name: grafana
+ app.kubernetes.io/instance: grafana
+ app.kubernetes.io/version: "10.1.5"
+ app.kubernetes.io/managed-by: Helm
+spec:
+ type: ClusterIP
+ ports:
+ - name: service
+ port: 3000
+ protocol: TCP
+ targetPort: 3000
+ selector:
+ app.kubernetes.io/name: grafana
+ app.kubernetes.io/instance: grafana
+---
+# Source: grafana/templates/deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: grafana
+ namespace: istio-system
+ labels:
+ helm.sh/chart: grafana-6.61.1
+ app.kubernetes.io/name: grafana
+ app.kubernetes.io/instance: grafana
+ app.kubernetes.io/version: "10.1.5"
+ app.kubernetes.io/managed-by: Helm
+spec:
+ replicas: 1
+ revisionHistoryLimit: 10
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: grafana
+ app.kubernetes.io/instance: grafana
+ strategy:
+ type: RollingUpdate
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/name: grafana
+ app.kubernetes.io/instance: grafana
+ sidecar.istio.io/inject: "false"
+ annotations:
+ checksum/config: e6dc57066020dcc7ec73db1b5e39370203985e5071b47f1f1414ee5c42679d46
+ checksum/dashboards-json-config: 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b
+ checksum/sc-dashboard-provider-config: 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b
+ kubectl.kubernetes.io/default-container: grafana
+ spec:
+
+ serviceAccountName: grafana
+ automountServiceAccountToken: true
+ enableServiceLinks: true
+ containers:
+ - name: grafana
+ image: "docker.io/grafana/grafana:10.1.5"
+ imagePullPolicy: IfNotPresent
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ seccompProfile:
+ type: RuntimeDefault
+ volumeMounts:
+ - name: config
+ mountPath: "/etc/grafana/grafana.ini"
+ subPath: grafana.ini
+ - name: storage
+ mountPath: "/var/lib/grafana"
+ - name: dashboards-istio
+ mountPath: "/var/lib/grafana/dashboards/istio"
+ - name: dashboards-istio-services
+ mountPath: "/var/lib/grafana/dashboards/istio-services"
+ - name: config
+ mountPath: "/etc/grafana/provisioning/datasources/datasources.yaml"
+ subPath: "datasources.yaml"
+ - name: config
+ mountPath: "/etc/grafana/provisioning/dashboards/dashboardproviders.yaml"
+ subPath: "dashboardproviders.yaml"
+ ports:
+ - name: grafana
+ containerPort: 3000
+ protocol: TCP
+ - name: gossip-tcp
+ containerPort: 9094
+ protocol: TCP
+ - name: gossip-udp
+ containerPort: 9094
+ protocol: UDP
+ env:
+ - name: POD_IP
+ valueFrom:
+ fieldRef:
+ fieldPath: status.podIP
+ - name: GF_PATHS_DATA
+ value: /var/lib/grafana/
+ - name: GF_PATHS_LOGS
+ value: /var/log/grafana
+ - name: GF_PATHS_PLUGINS
+ value: /var/lib/grafana/plugins
+ - name: GF_PATHS_PROVISIONING
+ value: /etc/grafana/provisioning
+ - name: "GF_AUTH_ANONYMOUS_ENABLED"
+ value: "true"
+ - name: "GF_AUTH_ANONYMOUS_ORG_ROLE"
+ value: "Admin"
+ - name: "GF_AUTH_BASIC_ENABLED"
+ value: "false"
+ - name: "GF_SECURITY_ADMIN_PASSWORD"
+ value: "admin"
+ - name: "GF_SECURITY_ADMIN_USER"
+ value: "admin"
+ livenessProbe:
+ failureThreshold: 10
+ httpGet:
+ path: /api/health
+ port: 3000
+ initialDelaySeconds: 60
+ timeoutSeconds: 30
+ readinessProbe:
+ httpGet:
+ path: /api/health
+ port: 3000
+ volumes:
+ - name: config
+ configMap:
+ name: grafana
+ - name: dashboards-istio
+ configMap:
+ name: istio-grafana-dashboards
+ - name: dashboards-istio-services
+ configMap:
+ name: istio-services-grafana-dashboards
+ - name: storage
+ emptyDir: {}
+
+---
+
+apiVersion: v1
+data:
+ istio-performance-dashboard.json: |
+ {"annotations":{"list":[{"builtIn":1,"datasource":"-- Grafana --","enable":true,"hide":true,"iconColor":"rgba(0, 211, 255, 1)","name":"Annotations & Alerts","type":"dashboard"}]},"editable":false,"gnetId":null,"graphTooltip":0,"links":[],"panels":[{"collapsed":true,"gridPos":{"h":1,"w":24,"x":0,"y":0},"id":21,"panels":[{"content":"The charts on this dashboard are intended to show Istio main components cost in terms of resources utilization under steady load.\n\n- **vCPU / 1k rps:** shows vCPU utilization by the main Istio components normalized by 1000 requests/second. When idle or low traffic, this chart will be blank. The curve for istio-proxy refers to the services sidecars only.\n- **vCPU:** vCPU utilization by Istio components, not normalized.\n- **Memory:** memory footprint for the components. Telemetry and policy are normalized by 1k rps, and no data is shown when there is no traffic. For ingress and istio-proxy, the data is per instance.\n- **Bytes transferred / sec:** shows the number of bytes flowing through each Istio component.\n\n\n","gridPos":{"h":6,"w":24,"x":0,"y":1},"id":19,"links":[],"mode":"markdown","timeFrom":null,"timeShift":null,"title":"Performance Dashboard README","transparent":true,"type":"text"}],"title":"Performance Dashboard Notes","type":"row"},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":1},"id":6,"panels":[],"title":"vCPU Usage","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":12,"x":0,"y":2},"id":4,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"(sum(irate(container_cpu_usage_seconds_total{pod=~\"istio-ingressgateway-.*\",container=\"istio-proxy\"}[1m])) / (round(sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m])), 0.001)/1000))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"istio-ingressgateway","refId":"A"},{"expr":"(sum(irate(container_cpu_usage_seconds_total{namespace!=\"istio-system\",container=\"istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)","format":"time_series","intervalFactor":1,"legendFormat":"istio-proxy","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"vCPU / 1k rps","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":12,"x":12,"y":2},"id":7,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(rate(container_cpu_usage_seconds_total{pod=~\"istio-ingressgateway-.*\",container=\"istio-proxy\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"istio-ingressgateway","refId":"A"},{"expr":"sum(rate(container_cpu_usage_seconds_total{namespace!=\"istio-system\",container=\"istio-proxy\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"istio-proxy","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"vCPU","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":10},"id":13,"panels":[],"title":"Memory and Data Rates","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":12,"x":0,"y":11},"id":902,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(container_memory_working_set_bytes{pod=~\"istio-ingressgateway-.*\"}) / count(container_memory_working_set_bytes{pod=~\"istio-ingressgateway-.*\",container!=\"POD\"})","format":"time_series","intervalFactor":1,"legendFormat":"per istio-ingressgateway","refId":"A"},{"expr":"sum(container_memory_working_set_bytes{namespace!=\"istio-system\",container=\"istio-proxy\"}) / count(container_memory_working_set_bytes{namespace!=\"istio-system\",container=\"istio-proxy\"})","format":"time_series","intervalFactor":1,"legendFormat":"per istio proxy","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Memory Usage","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":12,"x":12,"y":11},"id":11,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(irate(istio_response_bytes_sum{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"istio-ingressgateway","refId":"A"},{"expr":"sum(irate(istio_response_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_request_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"istio-proxy","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Bytes transferred / sec","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"Bps","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":19},"id":17,"panels":[],"title":"Istio Component Versions","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":24,"x":0,"y":20},"id":15,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(istio_build) by (component, tag)","format":"time_series","intervalFactor":1,"legendFormat":"{{ component }}: {{ tag }}","refId":"A"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Istio Components by Version","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":31},"id":71,"panels":[],"title":"Proxy Resource Usage","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":0,"y":32},"id":72,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(container_memory_working_set_bytes{container=\"istio-proxy\"})","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Total (k8s)","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Memory","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":6,"y":32},"id":73,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(rate(container_cpu_usage_seconds_total{container=\"istio-proxy\"}[1m]))","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Total (k8s)","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"vCPU","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":12,"y":32},"id":702,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(container_fs_usage_bytes{container=\"istio-proxy\"})","format":"time_series","intervalFactor":2,"legendFormat":"Total (k8s)","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Disk","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":"","logBase":1,"max":null,"min":null,"show":true},{"decimals":null,"format":"none","label":"","logBase":1024,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":39},"id":69,"panels":[],"title":"Istiod Resource Usage","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":0,"y":40},"id":5,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"process_virtual_memory_bytes{app=\"istiod\"}","format":"time_series","instant":false,"intervalFactor":2,"legendFormat":"Virtual Memory","refId":"I","step":2},{"expr":"process_resident_memory_bytes{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Resident Memory","refId":"H","step":2},{"expr":"go_memstats_heap_sys_bytes{app=\"istiod\"}","format":"time_series","hide":true,"intervalFactor":2,"legendFormat":"heap sys","refId":"A"},{"expr":"go_memstats_heap_alloc_bytes{app=\"istiod\"}","format":"time_series","hide":true,"intervalFactor":2,"legendFormat":"heap alloc","refId":"D"},{"expr":"go_memstats_alloc_bytes{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Alloc","refId":"F","step":2},{"expr":"go_memstats_heap_inuse_bytes{app=\"istiod\"}","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Heap in-use","refId":"E","step":2},{"expr":"go_memstats_stack_inuse_bytes{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Stack in-use","refId":"G","step":2},{"expr":"sum(container_memory_working_set_bytes{container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"})","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Total (k8s)","refId":"C","step":2},{"expr":"container_memory_working_set_bytes{container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"}","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"{{ container }} (k8s)","refId":"B","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Memory","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":6,"y":40},"id":602,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(rate(container_cpu_usage_seconds_total{container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"}[1m]))","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Total (k8s)","refId":"A","step":2},{"expr":"sum(rate(container_cpu_usage_seconds_total{container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"}[1m])) by (container)","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"{{ container }} (k8s)","refId":"B","step":2},{"expr":"irate(process_cpu_seconds_total{app=\"istiod\"}[1m])","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"pilot (self-reported)","refId":"C","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"vCPU","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":12,"y":40},"id":74,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"process_open_fds{app=\"istiod\"}","format":"time_series","hide":true,"instant":false,"interval":"","intervalFactor":2,"legendFormat":"Open FDs (pilot)","refId":"A"},{"expr":"container_fs_usage_bytes{ container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"}","format":"time_series","intervalFactor":2,"legendFormat":"{{ container }}","refId":"B","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Disk","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":"","logBase":1,"max":null,"min":null,"show":true},{"decimals":null,"format":"none","label":"","logBase":1024,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":18,"y":40},"id":402,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":false,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"go_goroutines{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Number of Goroutines","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Goroutines","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":"","logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}}],"refresh":"10s","schemaVersion":18,"style":"dark","tags":[],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"includeAll":false,"label":null,"multi":false,"name":"datasource","options":[],"query":"prometheus","queryValue":"","refresh":1,"regex":"","skipUrlSync":false,"type":"datasource"}]},"time":{"from":"now-5m","to":"now"},"timepicker":{"refresh_intervals":["5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"time_options":["5m","15m","1h","6h","12h","24h","2d","7d","30d"]},"timezone":"","title":"Istio Performance Dashboard","uid":"vu8e0VWZk","version":22}
+ pilot-dashboard.json: |
+ {"annotations":{"list":[{"builtIn":1,"datasource":"-- Grafana --","enable":true,"hide":true,"iconColor":"rgba(0, 211, 255, 1)","name":"Annotations & Alerts","type":"dashboard"}]},"editable":false,"gnetId":null,"graphTooltip":1,"links":[],"panels":[{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":0},"id":60,"panels":[],"title":"Deployed Versions","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":5,"w":24,"x":0,"y":1},"id":56,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(istio_build{component=\"pilot\"}) by (tag)","format":"time_series","intervalFactor":1,"legendFormat":"{{ tag }}","refId":"A"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Pilot Versions","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":6},"id":62,"panels":[],"title":"Resource Usage","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":0,"y":7},"id":5,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"process_virtual_memory_bytes{app=\"istiod\"}","format":"time_series","instant":false,"intervalFactor":2,"legendFormat":"Virtual Memory","refId":"I","step":2},{"expr":"process_resident_memory_bytes{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Resident Memory","refId":"H","step":2},{"expr":"go_memstats_heap_sys_bytes{app=\"istiod\"}","format":"time_series","hide":true,"intervalFactor":2,"legendFormat":"heap sys","refId":"A"},{"expr":"go_memstats_heap_alloc_bytes{app=\"istiod\"}","format":"time_series","hide":true,"intervalFactor":2,"legendFormat":"heap alloc","refId":"D"},{"expr":"go_memstats_alloc_bytes{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Alloc","refId":"F","step":2},{"expr":"go_memstats_heap_inuse_bytes{app=\"istiod\"}","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Heap in-use","refId":"E","step":2},{"expr":"go_memstats_stack_inuse_bytes{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Stack in-use","refId":"G","step":2},{"expr":"container_memory_working_set_bytes{container=~\"discovery\", pod=~\"istiod-.*|istio-pilot-.*\"}","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Discovery (container)","refId":"B","step":2},{"expr":"container_memory_working_set_bytes{container=~\"istio-proxy\", pod=~\"istiod-.*|istio-pilot-.*\"}","format":"time_series","intervalFactor":1,"legendFormat":"Sidecar (container)","refId":"C"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Memory","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":6,"y":7},"id":6,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(irate(container_cpu_usage_seconds_total{container=\"discovery\", pod=~\"istiod-.*|istio-pilot-.*\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Discovery (container)","refId":"A"},{"expr":"irate(process_cpu_seconds_total{app=\"istiod\"}[1m])","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Discovery (process)","refId":"C","step":2},{"expr":"sum(irate(container_cpu_usage_seconds_total{container=\"istio-proxy\", pod=~\"istiod-.*|istio-pilot-.*\"}[1m]))","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Sidecar (container)","refId":"B","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"CPU","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":12,"y":7},"id":7,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"container_fs_usage_bytes{container=\"discovery\", pod=~\"istiod-.*|istio-pilot-.*\"}","format":"time_series","intervalFactor":2,"legendFormat":"Discovery","refId":"B","step":2},{"expr":"container_fs_usage_bytes{container=\"istio-proxy\", pod=~\"istiod-.*|istio-pilot-.*\"}","format":"time_series","intervalFactor":1,"legendFormat":"Sidecar","refId":"A"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Disk","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"bytes","label":"","logBase":1,"max":null,"min":null,"show":true},{"decimals":null,"format":"none","label":"","logBase":1024,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":7,"w":6,"x":18,"y":7},"id":4,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":false,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"go_goroutines{app=\"istiod\"}","format":"time_series","intervalFactor":2,"legendFormat":"Number of Goroutines","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Goroutines","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":"","logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":14},"id":58,"panels":[],"title":"Pilot Push Information","type":"row"},{"aliasColors":{},"bars":true,"dashLength":10,"dashes":false,"datasource":"Prometheus","description":"Shows the rate of pilot pushes","fill":1,"gridPos":{"h":8,"w":8,"x":0,"y":15},"id":622,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":false,"linewidth":1,"links":[],"nullPointMode":"null as zero","paceLength":10,"percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":true,"steppedLine":false,"targets":[{"expr":"sum(irate(pilot_xds_pushes{type=\"cds\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Cluster","refId":"C"},{"expr":"sum(irate(pilot_xds_pushes{type=\"eds\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Endpoints","refId":"D"},{"expr":"sum(irate(pilot_xds_pushes{type=\"lds\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Listeners","refId":"A"},{"expr":"sum(irate(pilot_xds_pushes{type=\"rds\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Routes","refId":"E"},{"expr":"sum(irate(pilot_xds_pushes{type=\"sds\"}[1m]))","interval":"","legendFormat":"Secrets","refId":"B"},{"expr":"sum(irate(pilot_xds_pushes{type=\"nds\"}[1m]))","interval":"","legendFormat":"Nametables","refId":"F"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Pilot Pushes","tooltip":{"shared":false,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":["total"]},"yaxes":[{"format":"ops","label":null,"logBase":1,"max":null,"min":"0","show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","description":"Captures a variety of pilot errors","fill":1,"gridPos":{"h":8,"w":8,"x":8,"y":15},"id":67,"legend":{"avg":false,"current":false,"hideEmpty":true,"hideZero":true,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(pilot_xds_cds_reject{app=\"istiod\"}) or (absent(pilot_xds_cds_reject{app=\"istiod\"}) - 1)","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Rejected CDS Configs","refId":"C"},{"expr":"sum(pilot_xds_eds_reject{app=\"istiod\"}) or (absent(pilot_xds_eds_reject{app=\"istiod\"}) - 1)","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Rejected EDS Configs","refId":"D"},{"expr":"sum(pilot_xds_rds_reject{app=\"istiod\"}) or (absent(pilot_xds_rds_reject{app=\"istiod\"}) - 1)","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Rejected RDS Configs","refId":"A"},{"expr":"sum(pilot_xds_lds_reject{app=\"istiod\"}) or (absent(pilot_xds_lds_reject{app=\"istiod\"}) - 1)","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Rejected LDS Configs","refId":"B"},{"expr":"sum(rate(pilot_xds_write_timeout{app=\"istiod\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Write Timeouts","refId":"F"},{"expr":"sum(rate(pilot_total_xds_internal_errors{app=\"istiod\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Internal Errors","refId":"H"},{"expr":"sum(rate(pilot_total_xds_rejects{app=\"istiod\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Config Rejection Rate","refId":"E"},{"expr":"sum(rate(pilot_xds_push_context_errors{app=\"istiod\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Push Context Errors","refId":"K"},{"expr":"sum(rate(pilot_xds_write_timeout{app=\"istiod\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Push Timeouts","refId":"G"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Pilot Errors","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","description":"Shows the total time it takes to push a config update to a proxy","fill":1,"gridPos":{"h":8,"w":8,"x":16,"y":15},"id":624,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"histogram_quantile(0.5, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))","format":"time_series","intervalFactor":1,"legendFormat":"p50 ","refId":"A"},{"expr":"histogram_quantile(0.9, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))","format":"time_series","intervalFactor":1,"legendFormat":"p90","refId":"B"},{"expr":"histogram_quantile(0.99, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))","format":"time_series","intervalFactor":1,"legendFormat":"p99","refId":"C"},{"expr":"histogram_quantile(0.999, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))","format":"time_series","intervalFactor":1,"legendFormat":"p99.9","refId":"D"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Proxy Push Time","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"s","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":12,"x":0,"y":23},"id":45,"legend":{"avg":false,"current":false,"hideEmpty":true,"hideZero":true,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null as zero","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"pilot_conflict_inbound_listener{app=\"istiod\"}","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Inbound Listeners","refId":"B"},{"expr":"pilot_conflict_outbound_listener_tcp_over_current_tcp{app=\"istiod\"}","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"Outbound Listeners (tcp over current tcp)","refId":"C"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Conflicts","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":12,"x":12,"y":23},"id":47,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"avg(pilot_virt_services{app=\"istiod\"})","format":"time_series","intervalFactor":1,"legendFormat":"Virtual Services","refId":"A"},{"expr":"avg(pilot_services{app=\"istiod\"})","format":"time_series","intervalFactor":1,"legendFormat":"Services","refId":"B"},{"expr":"sum(pilot_xds{app=\"istiod\"}) by (pod)","format":"time_series","intervalFactor":1,"legendFormat":"Connected Endpoints {{pod}}","refId":"E"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"ADS Monitoring","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"gridPos":{"h":1,"w":24,"x":0,"y":31},"id":64,"panels":[],"title":"Envoy Information","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","description":"Shows details about Envoy proxies in the mesh","fill":1,"gridPos":{"h":8,"w":8,"x":0,"y":32},"id":40,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(irate(envoy_cluster_upstream_cx_total{cluster_name=\"xds-grpc\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"XDS Connections","refId":"C"},{"expr":"sum(irate(envoy_cluster_upstream_cx_connect_fail{cluster_name=\"xds-grpc\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"XDS Connection Failures","refId":"A"},{"expr":"sum(increase(envoy_server_hot_restart_epoch[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"Envoy Restarts","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Envoy Details","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"ops","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"ops","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":8,"w":8,"x":8,"y":32},"id":41,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(envoy_cluster_upstream_cx_active{cluster_name=\"xds-grpc\"})","format":"time_series","intervalFactor":2,"legendFormat":"XDS Active Connections","refId":"C","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"XDS Active Connections","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","description":"Shows the size of XDS requests and responses","fill":1,"gridPos":{"h":8,"w":8,"x":16,"y":32},"id":42,"legend":{"avg":false,"current":false,"hideEmpty":false,"hideZero":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"max(rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"XDS Response Bytes Max","refId":"D"},{"expr":"quantile(0.5, rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))","format":"time_series","hide":false,"intervalFactor":1,"legendFormat":"XDS Response Bytes Average","refId":"B"},{"expr":"max(rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"XDS Request Bytes Max","refId":"A"},{"expr":"quantile(.5, rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))","format":"time_series","intervalFactor":1,"legendFormat":"XDS Request Bytes Average","refId":"C"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"XDS Requests Size","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"Bps","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"ops","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"datasource":null,"gridPos":{"h":1,"w":24,"x":0,"y":40},"id":626,"panels":[],"title":"Webhooks","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":null,"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":12,"x":0,"y":41},"hiddenSeries":false,"id":629,"legend":{"avg":false,"current":false,"hideEmpty":false,"hideZero":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"dataLinks":[]},"percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(rate(galley_validation_passed[1m]))","interval":"","legendFormat":"Validations (Success)","refId":"A"},{"expr":"sum(rate(galley_validation_failed[1m]))","interval":"","legendFormat":"Validation (Failure)","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Configuration Validation","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":null,"description":"","fill":1,"fillGradient":0,"gridPos":{"h":8,"w":12,"x":12,"y":41},"hiddenSeries":false,"id":630,"legend":{"avg":false,"current":false,"hideZero":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"dataLinks":[]},"percentage":false,"pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(rate(sidecar_injection_success_total[1m]))","interval":"","legendFormat":"Injections (Success)","refId":"A"},{"expr":"sum(rate(sidecar_injection_failure_total[1m]))","interval":"","legendFormat":"Injections (Failure)","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Sidecar Injection","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}}],"refresh":"5s","schemaVersion":18,"style":"dark","tags":[],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"includeAll":false,"label":null,"multi":false,"name":"datasource","options":[],"query":"prometheus","queryValue":"","refresh":1,"regex":"","skipUrlSync":false,"type":"datasource"}]},"time":{"from":"now-5m","to":"now"},"timepicker":{"refresh_intervals":["5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"time_options":["5m","15m","1h","6h","12h","24h","2d","7d","30d"]},"timezone":"browser","title":"Istio Control Plane Dashboard","uid":"3--MLVZZk","version":11}
+kind: ConfigMap
+metadata:
+ creationTimestamp: null
+ name: istio-grafana-dashboards
+ namespace: istio-system
+
+---
+
+apiVersion: v1
+data:
+ istio-extension-dashboard.json: |
+ {"annotations":{"list":[{"builtIn":1,"datasource":"-- Grafana --","enable":true,"hide":true,"iconColor":"rgba(0, 211, 255, 1)","name":"Annotations & Alerts","type":"dashboard"}]},"editable":false,"gnetId":null,"graphTooltip":0,"links":[],"panels":[{"collapsed":false,"datasource":"Prometheus","gridPos":{"h":1,"w":24,"x":0,"y":0},"id":3,"panels":[],"title":"Wasm VMs","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","description":"","fieldConfig":{"defaults":{"custom":{"align":null},"links":[],"mappings":[],"thresholds":{"mode":"absolute","steps":[{"color":"green","value":null},{"color":"red","value":80}]}},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":12,"x":0,"y":1},"hiddenSeries":false,"id":2,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"avg(envoy_wasm_envoy_wasm_runtime_null_active)","interval":"","legendFormat":"native","refId":"A"},{"expr":"avg(envoy_wasm_envoy_wasm_runtime_v8_active)","interval":"","legendFormat":"v8","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Active","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:123","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:124","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fieldConfig":{"defaults":{"custom":{},"links":[]},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":12,"x":12,"y":1},"hiddenSeries":false,"id":6,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"avg(envoy_wasm_envoy_wasm_runtime_null_created)","interval":"","legendFormat":"native","refId":"A"},{"expr":"avg(envoy_wasm_envoy_wasm_runtime_v8_created)","interval":"","legendFormat":"v8","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Created","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:68","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:69","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"datasource":"Prometheus","gridPos":{"h":1,"w":24,"x":0,"y":9},"id":7,"panels":[],"title":"Wasm Module Remote Load","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fieldConfig":{"defaults":{"custom":{},"links":[]},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":8,"x":0,"y":10},"hiddenSeries":false,"id":11,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"avg(envoy_wasm_remote_load_cache_entries)","interval":"","legendFormat":"entries","refId":"A"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Cache Entry","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:178","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:179","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fieldConfig":{"defaults":{"custom":{},"links":[]},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":8,"x":8,"y":10},"hiddenSeries":false,"id":8,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"avg(envoy_wasm_remote_load_cache_hits)","interval":"","legendFormat":"hits","refId":"A"},{"expr":"avg(envoy_wasm_remote_load_cache_misses)","interval":"","legendFormat":"misses","refId":"B"},{"expr":"avg(envoy_wasm_remote_load_cache_negative_hits)","interval":"","legendFormat":"negative hits","refId":"C"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Cache Visit","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:233","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:234","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fieldConfig":{"defaults":{"custom":{},"links":[]},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":8,"x":16,"y":10},"hiddenSeries":false,"id":10,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":2,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"avg(envoy_wasm_remote_load_fetch_failures)","interval":"","legendFormat":"failures","refId":"A"},{"expr":"avg(envoy_wasm_remote_load_fetch_successes)","interval":"","legendFormat":"successes","refId":"B"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Remote Fetch","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:288","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:289","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}},{"collapsed":false,"datasource":"Prometheus","gridPos":{"h":1,"w":24,"x":0,"y":18},"id":71,"panels":[],"title":"Proxy Resource Usage","type":"row"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fieldConfig":{"defaults":{"custom":{}},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":12,"x":0,"y":19},"hiddenSeries":false,"id":72,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(container_memory_working_set_bytes{container=\"istio-proxy\"})","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Total (k8s)","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Memory","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:396","format":"bytes","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:397","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fieldConfig":{"defaults":{"custom":{}},"overrides":[]},"fill":1,"fillGradient":0,"gridPos":{"h":8,"w":12,"x":12,"y":19},"hiddenSeries":false,"id":73,"legend":{"avg":false,"current":false,"max":false,"min":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","options":{"alertThreshold":true},"percentage":false,"pluginVersion":"7.2.1","pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(rate(container_cpu_usage_seconds_total{container=\"istio-proxy\"}[1m]))","format":"time_series","hide":false,"intervalFactor":2,"legendFormat":"Total (k8s)","refId":"A","step":2}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"vCPU","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"$$hashKey":"object:447","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"$$hashKey":"object:448","format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true}],"yaxis":{"align":false,"alignLevel":null}}],"refresh":false,"schemaVersion":26,"style":"dark","tags":[],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"includeAll":false,"label":null,"multi":false,"name":"datasource","options":[],"query":"prometheus","queryValue":"","refresh":1,"regex":"","skipUrlSync":false,"type":"datasource"}]},"time":{"from":"now-5m","to":"now"},"timepicker":{"refresh_intervals":["10s","30s","1m","5m","15m","30m","1h","2h","1d"]},"timezone":"","title":"Istio Wasm Extension Dashboard","uid":"7PAV7ctGz","version":17}
+ istio-mesh-dashboard.json: |
+ {"annotations":{"list":[{"builtIn":1,"datasource":"-- Grafana --","enable":true,"hide":true,"iconColor":"rgba(0, 211, 255, 1)","name":"Annotations & Alerts","type":"dashboard"}]},"editable":false,"gnetId":null,"graphTooltip":0,"id":null,"links":[],"panels":[{"content":"","gridPos":{"h":3,"w":24,"x":0,"y":0},"height":"50px","id":13,"links":[],"mode":"html","style":{"font-size":"18pt"},"title":"","transparent":true,"type":"text"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"datasource":"Prometheus","format":"ops","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":0,"y":3},"id":20,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":true,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"round(sum(irate(istio_requests_total{reporter=\"source\"}[1m])), 0.001)","intervalFactor":1,"refId":"A","step":4}],"thresholds":"","title":"Global Request Volume","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"avg"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"datasource":"Prometheus","format":"percentunit","gauge":{"maxValue":100,"minValue":80,"show":false,"thresholdLabels":false,"thresholdMarkers":false},"gridPos":{"h":3,"w":6,"x":6,"y":3},"id":21,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":true,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"sum(rate(istio_requests_total{reporter=\"source\", response_code!~\"5.*\"}[1m])) / sum(rate(istio_requests_total{reporter=\"source\"}[1m]))","format":"time_series","intervalFactor":1,"refId":"A","step":4}],"thresholds":"95, 99, 99.5","title":"Global Success Rate (non-5xx responses)","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"avg"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"datasource":"Prometheus","format":"ops","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":12,"y":3},"id":22,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":true,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"sum(irate(istio_requests_total{reporter=\"source\", response_code=~\"4.*\"}[1m]))","format":"time_series","intervalFactor":1,"refId":"A","step":4}],"thresholds":"","title":"4xxs","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"avg"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"datasource":"Prometheus","format":"ops","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":18,"y":3},"id":23,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":true,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"sum(irate(istio_requests_total{reporter=\"source\", response_code=~\"5.*\"}[1m]))","format":"time_series","intervalFactor":1,"refId":"A","step":4}],"thresholds":"","title":"5xxs","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"avg"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":0,"y":6},"id":113,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"VirtualService\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"VirtualService\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"Virtual Services","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":6,"y":6},"id":114,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"DestinationRule\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"DestinationRule\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"Destination Rules","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":12,"y":6},"id":115,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"Gateway\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"Gateway\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"Gateways","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":18,"y":6},"id":116,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"WorkloadEntry\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"WorkloadEntry\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"Workload Entries","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":0,"y":6},"id":117,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"ServiceEntry\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"ServiceEntry\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"Service Entries","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":6,"y":6},"id":90,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"PeerAuthentication\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"PeerAuthentication\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"PeerAuthentication Policies","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":12,"y":6},"id":91,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"RequestAuthentication\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"RequestAuthentication\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"RequestAuthentication Policies","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"cacheTimeout":null,"colorBackground":false,"colorValue":false,"colors":["#299c46","rgba(237, 129, 40, 0.89)","#d44a3a"],"datasource":"Prometheus","format":"none","gauge":{"maxValue":100,"minValue":0,"show":false,"thresholdLabels":false,"thresholdMarkers":true},"gridPos":{"h":3,"w":6,"x":18,"y":6},"id":92,"interval":null,"links":[],"options":{"colorMode":"value","graphMode":"area","justifyMode":"auto","orientation":"horizontal","reduceOptions":{"calcs":["lastNotNull"],"fields":"","values":false},"textMode":"auto"},"mappingType":1,"mappingTypes":[{"name":"value to text","value":1},{"name":"range to text","value":2}],"maxDataPoints":100,"nullPointMode":"connected","nullText":null,"postfix":"","postfixFontSize":"50%","prefix":"","prefixFontSize":"50%","rangeMaps":[{"from":"null","text":"N/A","to":"null"}],"sparkline":{"fillColor":"rgba(31, 118, 189, 0.18)","full":false,"lineColor":"rgb(31, 120, 193)","show":true},"tableColumn":"","targets":[{"expr":"max(pilot_k8s_cfg_events{type=\"AuthorizationPolicy\", event=\"add\"}) - (max(pilot_k8s_cfg_events{type=\"AuthorizationPolicy\", event=\"delete\"}) or max(up * 0))","format":"time_series","intervalFactor":1,"refId":"A"}],"thresholds":"","timeFrom":null,"timeShift":null,"title":"Authorization Policies","type":"singlestat","valueFontSize":"80%","valueMaps":[{"op":"=","text":"N/A","value":"null"}],"valueName":"current"},{"columns":[],"datasource":"Prometheus","fontSize":"100%","gridPos":{"h":21,"w":24,"x":0,"y":9},"hideTimeOverride":false,"id":73,"links":[],"pageSize":null,"repeat":null,"repeatDirection":"v","scroll":true,"showHeader":true,"sort":{"col":5,"desc":true},"styles":[{"alias":"Workload","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"link":false,"linkTargetBlank":false,"linkTooltip":"Workload dashboard","linkUrl":"/dashboard/db/istio-workload-dashboard?var-namespace=${__cell_3:raw}&var-workload=${__cell_2:raw}","pattern":"destination_workload","preserveFormat":false,"sanitize":false,"thresholds":[],"type":"hidden","unit":"short"},{"alias":"","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Time","thresholds":[],"type":"hidden","unit":"short"},{"alias":"Requests","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #A","thresholds":[],"type":"number","unit":"ops"},{"alias":"P50 Latency","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #B","thresholds":[],"type":"number","unit":"s"},{"alias":"P90 Latency","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #C","thresholds":[],"type":"number","unit":"s"},{"alias":"P99 Latency","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #D","thresholds":[],"type":"number","unit":"s"},{"alias":"Success Rate","colorMode":"cell","colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #E","thresholds":[".95"," 1.00"],"type":"number","unit":"percentunit"},{"alias":"Workload","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"link":true,"linkTooltip":"$__cell dashboard","linkUrl":"/dashboard/db/istio-workload-dashboard?var-workload=${__cell_2:raw}&var-namespace=${__cell_3:raw}","pattern":"destination_workload_var","thresholds":[],"type":"number","unit":"short"},{"alias":"Service","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"link":true,"linkTooltip":"$__cell dashboard","linkUrl":"/dashboard/db/istio-service-dashboard?var-service=${__cell_1:raw}","pattern":"destination_service","thresholds":[],"type":"string","unit":"short"},{"alias":"","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"destination_workload_namespace","thresholds":[],"type":"hidden","unit":"short"}],"targets":[{"expr":"label_join(sum(rate(istio_requests_total{reporter=\"source\", response_code=\"200\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"intervalFactor":1,"legendFormat":"{{ destination_workload}}.{{ destination_workload_namespace }}","refId":"A"},{"expr":"label_join((histogram_quantile(0.50, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"source\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.50, sum(rate(istio_request_duration_seconds_bucket{reporter=\"source\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"intervalFactor":1,"legendFormat":"{{ destination_workload}}.{{ destination_workload_namespace }}","refId":"B"},{"expr":"label_join((histogram_quantile(0.90, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"source\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.90, sum(rate(istio_request_duration_seconds_bucket{reporter=\"source\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"intervalFactor":1,"legendFormat":"{{ destination_workload }}.{{ destination_workload_namespace }}","refId":"C"},{"expr":"label_join((histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"source\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.99, sum(rate(istio_request_duration_seconds_bucket{reporter=\"source\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"intervalFactor":1,"legendFormat":"{{ destination_workload }}.{{ destination_workload_namespace }}","refId":"D"},{"expr":"label_join((sum(rate(istio_requests_total{reporter=\"source\", response_code!~\"5.*\"}[1m])) by (destination_workload, destination_workload_namespace) / sum(rate(istio_requests_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"interval":"","intervalFactor":1,"legendFormat":"{{ destination_workload }}.{{ destination_workload_namespace }}","refId":"E"}],"timeFrom":null,"title":"HTTP/GRPC Workloads","transform":"table","type":"table"},{"columns":[],"datasource":"Prometheus","fontSize":"100%","gridPos":{"h":18,"w":24,"x":0,"y":30},"hideTimeOverride":false,"id":109,"links":[],"pageSize":null,"repeatDirection":"v","scroll":true,"showHeader":true,"sort":{"col":5,"desc":true},"styles":[{"alias":"Workload","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"link":false,"linkTargetBlank":false,"linkTooltip":"$__cell dashboard","linkUrl":"/dashboard/db/istio-workload-dashboard?var-namespace=${__cell_3:raw}&var-workload=${__cell_2:raw}","pattern":"destination_workload","preserveFormat":false,"sanitize":false,"thresholds":[],"type":"hidden","unit":"short"},{"alias":"Bytes Sent","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #A","thresholds":[""],"type":"number","unit":"Bps"},{"alias":"Bytes Received","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Value #B","thresholds":[],"type":"number","unit":"Bps"},{"alias":"","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"Time","thresholds":[],"type":"hidden","unit":"short"},{"alias":"Workload","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"link":true,"linkTooltip":"$__cell dashboard","linkUrl":"/dashboard/db/istio-workload-dashboard?var-namespace=${__cell_3:raw}&var-workload=${__cell_2:raw}","pattern":"destination_workload_var","thresholds":[],"type":"string","unit":"short"},{"alias":"","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"pattern":"destination_workload_namespace","thresholds":[],"type":"hidden","unit":"short"},{"alias":"Service","colorMode":null,"colors":["rgba(245, 54, 54, 0.9)","rgba(237, 129, 40, 0.89)","rgba(50, 172, 45, 0.97)"],"dateFormat":"YYYY-MM-DD HH:mm:ss","decimals":2,"link":true,"linkTooltip":"$__cell dashboard","linkUrl":"/dashboard/db/istio-service-dashboard?var-service=${__cell_1:raw}","pattern":"destination_service","thresholds":[],"type":"number","unit":"short"}],"targets":[{"expr":"label_join(sum(rate(istio_tcp_received_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"intervalFactor":1,"legendFormat":"{{ destination_workload }}","refId":"A"},{"expr":"label_join(sum(rate(istio_tcp_sent_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")","format":"table","hide":false,"instant":true,"intervalFactor":1,"legendFormat":"{{ destination_workload }}","refId":"B"}],"timeFrom":null,"title":"TCP Workloads","transform":"table","type":"table"},{"aliasColors":{},"bars":false,"dashLength":10,"dashes":false,"datasource":"Prometheus","fill":1,"gridPos":{"h":9,"w":24,"x":0,"y":48},"id":111,"legend":{"alignAsTable":false,"avg":false,"current":false,"max":false,"min":false,"rightSide":false,"show":true,"total":false,"values":false},"lines":true,"linewidth":1,"links":[],"nullPointMode":"null","percentage":false,"pointradius":5,"points":false,"renderer":"flot","seriesOverrides":[],"spaceLength":10,"stack":false,"steppedLine":false,"targets":[{"expr":"sum(istio_build) by (component, tag)","format":"time_series","intervalFactor":1,"legendFormat":"{{ component }}: {{ tag }}","refId":"A"}],"thresholds":[],"timeFrom":null,"timeRegions":[],"timeShift":null,"title":"Istio Components by Version","tooltip":{"shared":true,"sort":0,"value_type":"individual"},"type":"graph","xaxis":{"buckets":null,"mode":"time","name":null,"show":true,"values":[]},"yaxes":[{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":true},{"format":"short","label":null,"logBase":1,"max":null,"min":null,"show":false}],"yaxis":{"align":false,"alignLevel":null}}],"refresh":"5s","schemaVersion":18,"style":"dark","tags":[],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"includeAll":false,"label":null,"multi":false,"name":"datasource","options":[],"query":"prometheus","queryValue":"","refresh":1,"regex":"","skipUrlSync":false,"type":"datasource"}]},"time":{"from":"now-5m","to":"now"},"timepicker":{"refresh_intervals":["5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"time_options":["5m","15m","1h","6h","12h","24h","2d","7d","30d"]},"timezone":"browser","title":"Istio Mesh Dashboard","uid":"G8wLrJIZk","version":5}
+ istio-service-dashboard.json: "{\"annotations\":{\"list\":[{\"builtIn\":1,\"datasource\":\"--
+ Grafana --\",\"enable\":true,\"hide\":true,\"iconColor\":\"rgba(0, 211, 255, 1)\",\"name\":\"Annotations
+ & Alerts\",\"type\":\"dashboard\"}]},\"editable\":false,\"gnetId\":null,\"graphTooltip\":0,\"iteration\":1595591291797,\"links\":[],\"panels\":[{\"collapsed\":true,\"gridPos\":{\"h\":1,\"w\":24,\"x\":0,\"y\":0},\"id\":106,\"panels\":[{\"content\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"gridPos\":{\"h\":3,\"w\":24,\"x\":0,\"y\":1},\"id\":89,\"links\":[],\"mode\":\"html\",\"options\":{\"content\":\"\",\"mode\":\"html\"},\"pluginVersion\":\"7.1.0\",\"title\":\"\",\"transparent\":true,\"type\":\"text\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"rgba(245,
+ 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"ops\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":6,\"x\":0,\"y\":4},\"id\":12,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+ to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+ 118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[5m])),
+ 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"refId\":\"A\",\"step\":4}],\"thresholds\":\"\",\"title\":\"Client
+ Request Volume\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"current\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"rgba(50,
+ 172, 45, 0.97)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(245, 54, 54, 0.9)\"],\"datasource\":\"Prometheus\",\"decimals\":null,\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"percentunit\",\"gauge\":{\"maxValue\":100,\"minValue\":80,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":false},\"gridPos\":{\"h\":4,\"w\":6,\"x\":6,\"y\":4},\"id\":14,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+ to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+ 118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\",response_code!~\\\"5.*\\\"}[5m]))
+ / sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[5m]))\",\"format\":\"time_series\",\"intervalFactor\":1,\"refId\":\"A\"}],\"thresholds\":\"95,
+ 99, 99.5\",\"title\":\"Client Success Rate (non-5xx responses)\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":4,\"w\":6,\"x\":12,\"y\":4},\"hiddenSeries\":false,\"id\":87,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":false,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":true,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[1m]))
+ by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[1m]))
+ by (le))\",\"format\":\"time_series\",\"interval\":\"\",\"intervalFactor\":1,\"legendFormat\":\"P50\",\"refId\":\"A\"},{\"expr\":\"(histogram_quantile(0.90,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[1m]))
+ by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[1m]))
+ by (le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"P90\",\"refId\":\"B\"},{\"expr\":\"(histogram_quantile(0.99,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[1m]))
+ by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",destination_service=~\\\"$service\\\"}[1m]))
+ by (le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"P99\",\"refId\":\"C\"}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Client
+ Request Duration\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"#299c46\",\"rgba(237,
+ 129, 40, 0.89)\",\"#d44a3a\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"Bps\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":6,\"x\":18,\"y\":4},\"id\":84,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+ to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+ 118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\",
+ destination_service=~\\\"$service\\\"}[1m]))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"\",\"refId\":\"A\"}],\"thresholds\":\"\",\"title\":\"TCP
+ Received Bytes\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"rgba(245,
+ 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"ops\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":6,\"x\":0,\"y\":8},\"id\":97,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+ to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+ 118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[5m])),
+ 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"refId\":\"A\",\"step\":4}],\"thresholds\":\"\",\"title\":\"Server
+ Request Volume\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"current\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"rgba(50,
+ 172, 45, 0.97)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(245, 54, 54, 0.9)\"],\"datasource\":\"Prometheus\",\"decimals\":null,\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"percentunit\",\"gauge\":{\"maxValue\":100,\"minValue\":80,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":false},\"gridPos\":{\"h\":4,\"w\":6,\"x\":6,\"y\":8},\"id\":98,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+ to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+ 118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\",response_code!~\\\"5.*\\\"}[5m]))
+ / sum(irate(istio_requests_total{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[5m]))\",\"format\":\"time_series\",\"intervalFactor\":1,\"refId\":\"A\"}],\"thresholds\":\"95,
+ 99, 99.5\",\"title\":\"Server Success Rate (non-5xx responses)\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":4,\"w\":6,\"x\":12,\"y\":8},\"hiddenSeries\":false,\"id\":99,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":false,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":true,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[1m]))
+ by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[1m]))
+ by (le))\",\"format\":\"time_series\",\"interval\":\"\",\"intervalFactor\":1,\"legendFormat\":\"P50\",\"refId\":\"A\"},{\"expr\":\"(histogram_quantile(0.90,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[1m]))
+ by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[1m]))
+ by (le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"P90\",\"refId\":\"B\"},{\"expr\":\"(histogram_quantile(0.99,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[1m]))
+ by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",destination_service=~\\\"$service\\\"}[1m]))
+ by (le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"P99\",\"refId\":\"C\"}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Server
+ Request Duration\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"#299c46\",\"rgba(237,
+ 129, 40, 0.89)\",\"#d44a3a\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"Bps\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":6,\"x\":18,\"y\":8},\"id\":100,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+ to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+ 118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+ destination_service=~\\\"$service\\\"}[1m]))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"\",\"refId\":\"A\"}],\"thresholds\":\"\",\"title\":\"TCP
+ Sent Bytes\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"}],\"title\":\"General\",\"type\":\"row\"},{\"collapsed\":true,\"gridPos\":{\"h\":1,\"w\":24,\"x\":0,\"y\":1},\"id\":104,\"panels\":[{\"content\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"gridPos\":{\"h\":3,\"w\":24,\"x\":0,\"y\":2},\"id\":45,\"links\":[],\"mode\":\"html\",\"options\":{\"content\":\"\",\"mode\":\"html\"},\"pluginVersion\":\"7.1.0\",\"title\":\"\",\"transparent\":true,\"type\":\"text\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":0,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":5},\"hiddenSeries\":false,\"id\":25,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null
+ as zero\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{connection_security_policy=\\\"mutual_tls\\\",destination_service=~\\\"$service\\\",reporter=~\\\"$qrep\\\",source_workload=~\\\"$srcwl\\\",source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+ by (source_workload, source_workload_namespace, response_code), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_requests_total{connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", reporter=~\\\"$qrep\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[5m])) by (source_workload, source_workload_namespace,
+ response_code), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+ Requests By Source And Response Code\",\"tooltip\":{\"shared\":false,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[\"total\"]},\"yaxes\":[{\"format\":\"ops\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":5},\"hiddenSeries\":false,\"id\":26,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",response_code!~\\\"5.*\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+ by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+ by (source_workload, source_workload_namespace)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",response_code!~\\\"5.*\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+ by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+ by (source_workload, source_workload_namespace)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+ Success Rate (non-5xx responses) By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"percentunit\",\"label\":null,\"logBase\":1,\"max\":\"1.01\",\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"description\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":0,\"y\":11},\"hiddenSeries\":false,\"id\":27,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"(histogram_quantile(0.50,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+ Request Duration By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":8,\"y\":11},\"hiddenSeries\":false,\"id\":28,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+ sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ \ P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+ sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+ sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ \ P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+ Request Size By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":16,\"y\":11},\"hiddenSeries\":false,\"id\":68,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+ sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ \ P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+ sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+ sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ \ P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Response
+ Size By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":17},\"hiddenSeries\":false,\"id\":80,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace}} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace}}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+ Received from Incoming TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":17},\"hiddenSeries\":false,\"id\":82,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\\\"mutual_tls\\\",
+ reporter=~\\\"$qrep\\\", destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace),
+ 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace}} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\\\"mutual_tls\\\",
+ reporter=~\\\"$qrep\\\", destination_service=~\\\"$service\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace),
+ 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace}}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+ Sent to Incoming TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}}],\"title\":\"Client
+ Workloads\",\"type\":\"row\"},{\"collapsed\":true,\"gridPos\":{\"h\":1,\"w\":24,\"x\":0,\"y\":2},\"id\":102,\"panels\":[{\"content\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"gridPos\":{\"h\":3,\"w\":24,\"x\":0,\"y\":3},\"id\":69,\"links\":[],\"mode\":\"html\",\"options\":{\"content\":\"\",\"mode\":\"html\"},\"pluginVersion\":\"7.1.0\",\"title\":\"\",\"transparent\":true,\"type\":\"text\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":0,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":6},\"hiddenSeries\":false,\"id\":90,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null
+ as zero\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{connection_security_policy=\\\"mutual_tls\\\",destination_service=~\\\"$service\\\",reporter=\\\"destination\\\",destination_workload=~\\\"$dstwl\\\",destination_workload_namespace=~\\\"$dstns\\\"}[5m]))
+ by (destination_workload, destination_workload_namespace, response_code), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code
+ }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_requests_total{connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", reporter=\\\"destination\\\", destination_workload=~\\\"$dstwl\\\",
+ destination_workload_namespace=~\\\"$dstns\\\"}[5m])) by (destination_workload,
+ destination_workload_namespace, response_code), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code
+ }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+ Requests By Destination Workload And Response Code\",\"tooltip\":{\"shared\":false,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[\"total\"]},\"yaxes\":[{\"format\":\"ops\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":6},\"hiddenSeries\":false,\"id\":91,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=\\\"destination\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",response_code!~\\\"5.*\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[5m]))
+ by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\\\"destination\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[5m]))
+ by (destination_workload, destination_workload_namespace)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"sum(irate(istio_requests_total{reporter=\\\"destination\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",response_code!~\\\"5.*\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[5m]))
+ by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\\\"destination\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[5m]))
+ by (destination_workload, destination_workload_namespace)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+ Success Rate (non-5xx responses) By Destination Workload\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"percentunit\",\"label\":null,\"logBase\":1,\"max\":\"1.01\",\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"description\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":0,\"y\":12},\"hiddenSeries\":false,\"id\":94,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"(histogram_quantile(0.50,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99,
+ sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"destination\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+ Request Duration By Service Workload\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":8,\"y\":12},\"hiddenSeries\":false,\"id\":95,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+ Request Size By Service Workload\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":16,\"y\":12},\"hiddenSeries\":false,\"id\":96,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"destination\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace }} P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Response
+ Size By Service Workload\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":18},\"hiddenSeries\":false,\"id\":92,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{reporter=\\\"destination\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace}} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{reporter=\\\"destination\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_service=~\\\"$service\\\",
+ destination_workload=~\\\"$dstwl\\\", destination_workload_namespace=~\\\"$dstns\\\"}[1m]))
+ by (destination_workload, destination_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{ destination_workload_namespace}}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+ Received from Incoming TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":18},\"hiddenSeries\":false,\"id\":93,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\\\"mutual_tls\\\",
+ reporter=\\\"destination\\\", destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\",
+ destination_workload_namespace=~\\\"$dstns\\\"}[1m])) by (destination_workload,
+ destination_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{destination_workload_namespace }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\\\"mutual_tls\\\",
+ reporter=\\\"destination\\\", destination_service=~\\\"$service\\\", destination_workload=~\\\"$dstwl\\\",
+ destination_workload_namespace=~\\\"$dstns\\\"}[1m])) by (destination_workload,
+ destination_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_workload }}.{{destination_workload_namespace }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+ Sent to Incoming TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}}],\"title\":\"Service
+ Workloads\",\"type\":\"row\"}],\"refresh\":\"1m\",\"schemaVersion\":26,\"style\":\"dark\",\"tags\":[],\"templating\":{\"list\":[{\"current\":{\"selected\":true,\"text\":\"default\",\"value\":\"default\"},\"hide\":0,\"includeAll\":false,\"label\":null,\"multi\":false,\"name\":\"datasource\",\"options\":[],\"query\":\"prometheus\",\"queryValue\":\"\",\"refresh\":1,\"regex\":\"\",\"skipUrlSync\":false,\"type\":\"datasource\"},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":false,\"label\":\"Service\",\"multi\":false,\"name\":\"service\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{})
+ by (destination_service) or sum(istio_tcp_sent_bytes_total{}) by (destination_service))\",\"refresh\":1,\"regex\":\"/.*destination_service=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":0,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{\"selected\":true,\"text\":\"destination\",\"value\":\"destination\"},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":false,\"label\":\"Reporter\",\"multi\":true,\"name\":\"qrep\",\"query\":\"source,destination\",\"refresh\":1,\"regex\":\"\",\"skipUrlSync\":false,\"sort\":1,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"custom\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Client
+ Cluster\",\"multi\":true,\"name\":\"srccluster\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=~\\\"$qrep\\\",
+ destination_service=\\\"$service\\\"}) by (source_cluster) or sum(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+ destination_service=~\\\"$service\\\"}) by (source_cluster))\",\"refresh\":1,\"regex\":\"/.*cluster=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":2,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Client
+ Workload Namespace\",\"multi\":true,\"name\":\"srcns\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=~\\\"$qrep\\\",
+ destination_service=\\\"$service\\\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+ destination_service=~\\\"$service\\\"}) by (source_workload_namespace))\",\"refresh\":1,\"regex\":\"/.*namespace=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":3,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Client
+ Workload\",\"multi\":true,\"name\":\"srcwl\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=~\\\"$qrep\\\",
+ destination_service=~\\\"$service\\\", source_workload_namespace=~\\\"$srcns\\\"})
+ by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+ destination_service=~\\\"$service\\\", source_workload_namespace=~\\\"$srcns\\\"})
+ by (source_workload))\",\"refresh\":1,\"regex\":\"/.*workload=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":4,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Service
+ Workload Cluster\",\"multi\":true,\"name\":\"dstcluster\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=\\\"destination\\\",
+ destination_service=\\\"$service\\\"}) by (destination_cluster) or sum(istio_tcp_sent_bytes_total{reporter=\\\"destination\\\",
+ destination_service=~\\\"$service\\\"}) by (destination_cluster))\",\"refresh\":1,\"regex\":\"/.*cluster=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":2,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Service
+ Workload Namespace\",\"multi\":true,\"name\":\"dstns\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=\\\"destination\\\",
+ destination_service=\\\"$service\\\"}) by (destination_workload_namespace) or
+ sum(istio_tcp_sent_bytes_total{reporter=\\\"destination\\\", destination_service=~\\\"$service\\\"})
+ by (destination_workload_namespace))\",\"refresh\":1,\"regex\":\"/.*namespace=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":3,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Service
+ Workload\",\"multi\":true,\"name\":\"dstwl\",\"options\":[],\"query\":\"query_result(
+ sum(istio_requests_total{reporter=\\\"destination\\\", destination_service=~\\\"$service\\\",
+ destination_cluster=~\\\"$dstcluster\\\", destination_workload_namespace=~\\\"$dstns\\\"})
+ by (destination_workload) or sum(istio_tcp_sent_bytes_total{reporter=\\\"destination\\\",
+ destination_service=~\\\"$service\\\", destination_cluster=~\\\"$dstcluster\\\",
+ destination_workload_namespace=~\\\"$dstns\\\"}) by (destination_workload))\",\"refresh\":1,\"regex\":\"/.*workload=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":4,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false}]},\"time\":{\"from\":\"now-5m\",\"to\":\"now\"},\"timepicker\":{\"refresh_intervals\":[\"5m\",\"15m\",\"30m\",\"1h\",\"2h\",\"1d\"],\"time_options\":[\"5m\",\"15m\",\"1h\",\"6h\",\"12h\",\"24h\",\"2d\",\"7d\",\"30d\"]},\"timezone\":\"\",\"title\":\"Istio
+ Service Dashboard\",\"uid\":\"LJ_uJAvmk\",\"version\":1}\n"
+ istio-workload-dashboard.json: "{\"annotations\":{\"list\":[{\"builtIn\":1,\"datasource\":\"--
+ Grafana --\",\"enable\":true,\"hide\":true,\"iconColor\":\"rgba(0, 211, 255, 1)\",\"name\":\"Annotations
+ & Alerts\",\"type\":\"dashboard\"}]},\"editable\":false,\"gnetId\":null,\"graphTooltip\":0,\"iteration\":1531345461465,\"links\":[],\"panels\":[{\"collapsed\":true,\"gridPos\":{\"h\":1,\"w\":24,\"x\":0,\"y\":0},\"id\":95,\"panels\":[{\"content\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"gridPos\":{\"h\":3,\"w\":24,\"x\":0,\"y\":1},\"id\":89,\"links\":[],\"mode\":\"html\",\"options\":{\"content\":\"\",\"mode\":\"html\"},\"pluginVersion\":\"7.1.0\",\"title\":\"\",\"transparent\":true,\"type\":\"text\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"rgba(245,
+ 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"ops\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":8,\"x\":0,\"y\":4},\"id\":12,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+ to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+ 118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",destination_workload_namespace=~\\\"$namespace\\\",destination_workload=~\\\"$workload\\\"}[5m])),
+ 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"refId\":\"A\",\"step\":4}],\"thresholds\":\"\",\"title\":\"Incoming
+ Request Volume\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"current\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"rgba(50,
+ 172, 45, 0.97)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(245, 54, 54, 0.9)\"],\"datasource\":\"Prometheus\",\"decimals\":null,\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"percentunit\",\"gauge\":{\"maxValue\":100,\"minValue\":80,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":false},\"gridPos\":{\"h\":4,\"w\":8,\"x\":8,\"y\":4},\"id\":14,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+ to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+ 118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",destination_workload_namespace=~\\\"$namespace\\\",destination_workload=~\\\"$workload\\\",response_code!~\\\"5.*\\\"}[5m]))
+ / sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",destination_workload_namespace=~\\\"$namespace\\\",destination_workload=~\\\"$workload\\\"}[5m]))\",\"format\":\"time_series\",\"intervalFactor\":1,\"refId\":\"A\"}],\"thresholds\":\"95,
+ 99, 99.5\",\"title\":\"Incoming Success Rate (non-5xx responses)\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":4,\"w\":8,\"x\":16,\"y\":4},\"hiddenSeries\":false,\"id\":87,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":false,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":true,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\"}[1m])) by (le)) / 1000) or
+ histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\"}[1m])) by (le))\",\"format\":\"time_series\",\"interval\":\"\",\"intervalFactor\":1,\"legendFormat\":\"P50\",\"refId\":\"A\"},{\"expr\":\"(histogram_quantile(0.90,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\"}[1m])) by (le)) / 1000) or
+ histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\"}[1m])) by (le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"P90\",\"refId\":\"B\"},{\"expr\":\"(histogram_quantile(0.99,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\"}[1m])) by (le)) / 1000) or
+ histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\"}[1m])) by (le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"P99\",\"refId\":\"C\"}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Request
+ Duration\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"#299c46\",\"rgba(237,
+ 129, 40, 0.89)\",\"#d44a3a\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"Bps\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":12,\"x\":0,\"y\":8},\"id\":84,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+ to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+ 118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\"}[1m]))
+ + sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ destination_workload=~\\\"$workload\\\"}[1m]))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"\",\"refId\":\"A\"}],\"thresholds\":\"\",\"title\":\"TCP
+ Server Traffic\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"},{\"cacheTimeout\":null,\"colorBackground\":false,\"colorValue\":false,\"colors\":[\"#299c46\",\"rgba(237,
+ 129, 40, 0.89)\",\"#d44a3a\"],\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"format\":\"Bps\",\"gauge\":{\"maxValue\":100,\"minValue\":0,\"show\":false,\"thresholdLabels\":false,\"thresholdMarkers\":true},\"gridPos\":{\"h\":4,\"w\":12,\"x\":12,\"y\":8},\"id\":85,\"interval\":null,\"links\":[],\"options\":{\"colorMode\":\"value\",\"graphMode\":\"area\",\"justifyMode\":\"auto\",\"orientation\":\"horizontal\",\"reduceOptions\":{\"calcs\":[\"lastNotNull\"],\"fields\":\"\",\"values\":false},\"textMode\":\"auto\"},\"mappingType\":1,\"mappingTypes\":[{\"name\":\"value
+ to text\",\"value\":1},{\"name\":\"range to text\",\"value\":2}],\"maxDataPoints\":100,\"nullPointMode\":\"connected\",\"nullText\":null,\"postfix\":\"\",\"postfixFontSize\":\"50%\",\"prefix\":\"\",\"prefixFontSize\":\"50%\",\"rangeMaps\":[{\"from\":\"null\",\"text\":\"N/A\",\"to\":\"null\"}],\"sparkline\":{\"fillColor\":\"rgba(31,
+ 118, 189, 0.18)\",\"full\":true,\"lineColor\":\"rgb(31, 120, 193)\",\"show\":true},\"tableColumn\":\"\",\"targets\":[{\"expr\":\"sum(irate(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+ source_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$workload\\\"}[1m]))
+ + sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\", source_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$workload\\\"}[1m]))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"\",\"refId\":\"A\"}],\"thresholds\":\"\",\"title\":\"TCP
+ Client Traffic\",\"type\":\"singlestat\",\"valueFontSize\":\"80%\",\"valueMaps\":[{\"op\":\"=\",\"text\":\"N/A\",\"value\":\"null\"}],\"valueName\":\"avg\"}],\"title\":\"General\",\"type\":\"row\"},{\"collapsed\":true,\"gridPos\":{\"h\":1,\"w\":24,\"x\":0,\"y\":1},\"id\":93,\"panels\":[{\"content\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"gridPos\":{\"h\":3,\"w\":24,\"x\":0,\"y\":13},\"id\":45,\"links\":[],\"mode\":\"html\",\"options\":{\"content\":\"\",\"mode\":\"html\"},\"pluginVersion\":\"7.1.0\",\"title\":\"\",\"transparent\":true,\"type\":\"text\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":0,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":16},\"hiddenSeries\":false,\"id\":25,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null
+ as zero\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{connection_security_policy=\\\"mutual_tls\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\",
+ reporter=~\\\"$qrep\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+ by (source_workload, source_workload_namespace, response_code), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_requests_total{connection_security_policy!=\\\"mutual_tls\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\",
+ reporter=~\\\"$qrep\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+ by (source_workload, source_workload_namespace, response_code), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+ Requests By Source And Response Code\",\"tooltip\":{\"shared\":false,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[\"total\"]},\"yaxes\":[{\"format\":\"ops\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":16},\"hiddenSeries\":false,\"id\":26,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ destination_workload=~\\\"$workload\\\",response_code!~\\\"5.*\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[5m])) by (source_workload, source_workload_namespace)
+ / sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+ by (source_workload, source_workload_namespace)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ destination_workload=~\\\"$workload\\\",response_code!~\\\"5.*\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[5m])) by (source_workload, source_workload_namespace)
+ / sum(irate(istio_requests_total{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[5m]))
+ by (source_workload, source_workload_namespace)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+ Success Rate (non-5xx responses) By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"percentunit\",\"label\":null,\"logBase\":1,\"max\":\"1.01\",\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"description\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":0,\"y\":22},\"hiddenSeries\":false,\"id\":27,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"(histogram_quantile(0.50,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+ Request Duration By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":8,\"y\":22},\"hiddenSeries\":false,\"id\":28,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+ sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ \ P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+ sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+ sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ \ P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Incoming
+ Request Size By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":16,\"y\":22},\"hiddenSeries\":false,\"id\":68,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+ sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ \ P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+ sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+ sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy=\\\"mutual_tls\\\",
+ destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ \ P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ destination_workload=~\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload=~\\\"$workload\\\",
+ destination_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$srcwl\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}[1m])) by (source_workload, source_workload_namespace,
+ le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{source_workload}}.{{source_workload_namespace}}
+ P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Response
+ Size By Source\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":28},\"hiddenSeries\":false,\"id\":80,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\",
+ connection_security_policy=\\\"mutual_tls\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ destination_workload=~\\\"$workload\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace}} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{reporter=~\\\"$qrep\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ destination_workload=~\\\"$workload\\\", source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace}}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+ Received from Incoming TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":28},\"hiddenSeries\":false,\"id\":82,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\\\"mutual_tls\\\",
+ reporter=~\\\"$qrep\\\", destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace}} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\\\"mutual_tls\\\",
+ reporter=~\\\"$qrep\\\", destination_workload_namespace=~\\\"$namespace\\\", destination_workload=~\\\"$workload\\\",
+ source_workload=~\\\"$srcwl\\\", source_workload_namespace=~\\\"$srcns\\\"}[1m]))
+ by (source_workload, source_workload_namespace), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ source_workload }}.{{ source_workload_namespace}}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+ Sent to Incoming TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}}],\"title\":\"Inbound
+ Workloads\",\"type\":\"row\"},{\"collapsed\":true,\"gridPos\":{\"h\":1,\"w\":24,\"x\":0,\"y\":2},\"id\":91,\"panels\":[{\"content\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"gridPos\":{\"h\":3,\"w\":24,\"x\":0,\"y\":14},\"id\":69,\"links\":[],\"mode\":\"html\",\"options\":{\"content\":\"\",\"mode\":\"html\"},\"pluginVersion\":\"7.1.0\",\"title\":\"\",\"transparent\":true,\"type\":\"text\"},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":0,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":17},\"hiddenSeries\":false,\"id\":70,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null
+ as zero\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_requests_total{destination_principal=~\\\"spiffe.*\\\",
+ source_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$workload\\\",
+ reporter=\\\"source\\\", destination_service=~\\\"$dstsvc\\\"}[5m])) by (destination_service,
+ response_code), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} : {{ response_code }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_requests_total{destination_principal!~\\\"spiffe.*\\\",
+ source_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$workload\\\",
+ reporter=\\\"source\\\", destination_service=~\\\"$dstsvc\\\"}[5m])) by (destination_service,
+ response_code), 0.001)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} : {{ response_code }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Outgoing
+ Requests By Destination And Response Code\",\"tooltip\":{\"shared\":false,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[\"total\"]},\"yaxes\":[{\"format\":\"ops\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":17},\"hiddenSeries\":false,\"id\":71,\"legend\":{\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"sum(irate(istio_requests_total{reporter=\\\"source\\\",
+ connection_security_policy=\\\"mutual_tls\\\", source_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$workload\\\",response_code!~\\\"5.*\\\", destination_service=~\\\"$dstsvc\\\"}[5m]))
+ by (destination_service) / sum(irate(istio_requests_total{reporter=\\\"source\\\",
+ connection_security_policy=\\\"mutual_tls\\\", source_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$workload\\\", destination_service=~\\\"$dstsvc\\\"}[5m]))
+ by (destination_service)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"sum(irate(istio_requests_total{reporter=\\\"source\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", source_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$workload\\\",response_code!~\\\"5.*\\\", destination_service=~\\\"$dstsvc\\\"}[5m]))
+ by (destination_service) / sum(irate(istio_requests_total{reporter=\\\"source\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", source_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$workload\\\", destination_service=~\\\"$dstsvc\\\"}[5m]))
+ by (destination_service)\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Outgoing
+ Success Rate (non-5xx responses) By Destination\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"percentunit\",\"label\":null,\"logBase\":1,\"max\":\"1.01\",\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"description\":\"\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":0,\"y\":23},\"hiddenSeries\":false,\"id\":72,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"hideZero\":false,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"(histogram_quantile(0.50,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"(histogram_quantile(0.50,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"(histogram_quantile(0.90,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"(histogram_quantile(0.95,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"(histogram_quantile(0.99,
+ sum(irate(istio_request_duration_milliseconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\\\"source\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", source_workload=~\\\"$workload\\\",
+ source_workload_namespace=~\\\"$namespace\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Outgoing
+ Request Duration By Destination\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"s\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":8,\"y\":23},\"hiddenSeries\":false,\"id\":73,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+ sum(irate(istio_request_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Outgoing
+ Request Size By Destination\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":8,\"x\":16,\"y\":23},\"hiddenSeries\":false,\"id\":74,\"legend\":{\"alignAsTable\":false,\"avg\":false,\"current\":false,\"hideEmpty\":true,\"max\":false,\"min\":false,\"rightSide\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P50 (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P90 (\U0001F510mTLS)\",\"refId\":\"B\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P95 (\U0001F510mTLS)\",\"refId\":\"C\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P99 (\U0001F510mTLS)\",\"refId\":\"D\",\"step\":2},{\"expr\":\"histogram_quantile(0.50,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P50\",\"refId\":\"E\",\"step\":2},{\"expr\":\"histogram_quantile(0.90,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P90\",\"refId\":\"F\",\"step\":2},{\"expr\":\"histogram_quantile(0.95,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P95\",\"refId\":\"G\",\"step\":2},{\"expr\":\"histogram_quantile(0.99,
+ sum(irate(istio_response_bytes_bucket{reporter=\\\"source\\\", connection_security_policy!=\\\"mutual_tls\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service, le))\",\"format\":\"time_series\",\"hide\":false,\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} P99\",\"refId\":\"H\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Response
+ Size By Destination\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"decbytes\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":false}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":0,\"y\":29},\"hiddenSeries\":false,\"id\":76,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{connection_security_policy=\\\"mutual_tls\\\",
+ reporter=\\\"source\\\", source_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$workload\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_received_bytes_total{connection_security_policy!=\\\"mutual_tls\\\",
+ reporter=\\\"source\\\", source_workload_namespace=~\\\"$namespace\\\", source_workload=~\\\"$workload\\\",
+ destination_service=~\\\"$dstsvc\\\"}[1m])) by (destination_service), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+ Sent on Outgoing TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}},{\"aliasColors\":{},\"bars\":false,\"dashLength\":10,\"dashes\":false,\"datasource\":\"Prometheus\",\"fieldConfig\":{\"defaults\":{\"custom\":{}},\"overrides\":[]},\"fill\":1,\"fillGradient\":0,\"gridPos\":{\"h\":6,\"w\":12,\"x\":12,\"y\":29},\"hiddenSeries\":false,\"id\":78,\"legend\":{\"avg\":false,\"current\":false,\"max\":false,\"min\":false,\"show\":true,\"total\":false,\"values\":false},\"lines\":true,\"linewidth\":1,\"links\":[],\"nullPointMode\":\"null\",\"percentage\":false,\"pluginVersion\":\"7.1.0\",\"pointradius\":5,\"points\":false,\"renderer\":\"flot\",\"seriesOverrides\":[],\"spaceLength\":10,\"stack\":false,\"steppedLine\":false,\"targets\":[{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{reporter=\\\"source\\\",
+ connection_security_policy=\\\"mutual_tls\\\", source_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$workload\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }} (\U0001F510mTLS)\",\"refId\":\"A\",\"step\":2},{\"expr\":\"round(sum(irate(istio_tcp_sent_bytes_total{reporter=\\\"source\\\",
+ connection_security_policy!=\\\"mutual_tls\\\", source_workload_namespace=~\\\"$namespace\\\",
+ source_workload=~\\\"$workload\\\", destination_service=~\\\"$dstsvc\\\"}[1m]))
+ by (destination_service), 0.001)\",\"format\":\"time_series\",\"intervalFactor\":1,\"legendFormat\":\"{{
+ destination_service }}\",\"refId\":\"B\",\"step\":2}],\"thresholds\":[],\"timeFrom\":null,\"timeRegions\":[],\"timeShift\":null,\"title\":\"Bytes
+ Received from Outgoing TCP Connection\",\"tooltip\":{\"shared\":true,\"sort\":0,\"value_type\":\"individual\"},\"type\":\"graph\",\"xaxis\":{\"buckets\":null,\"mode\":\"time\",\"name\":null,\"show\":true,\"values\":[]},\"yaxes\":[{\"format\":\"Bps\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":\"0\",\"show\":true},{\"format\":\"short\",\"label\":null,\"logBase\":1,\"max\":null,\"min\":null,\"show\":true}],\"yaxis\":{\"align\":false,\"alignLevel\":null}}],\"title\":\"Outbound
+ Services\",\"type\":\"row\"}],\"refresh\":\"1m\",\"schemaVersion\":26,\"style\":\"dark\",\"tags\":[],\"templating\":{\"list\":[{\"current\":{\"selected\":true,\"text\":\"default\",\"value\":\"default\"},\"hide\":0,\"includeAll\":false,\"label\":null,\"multi\":false,\"name\":\"datasource\",\"options\":[],\"query\":\"prometheus\",\"queryValue\":\"\",\"refresh\":1,\"regex\":\"\",\"skipUrlSync\":false,\"type\":\"datasource\"},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":false,\"label\":\"Namespace\",\"multi\":false,\"name\":\"namespace\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total)
+ by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total) by (destination_workload_namespace))\",\"refresh\":1,\"regex\":\"/.*_namespace=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":0,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":false,\"label\":\"Workload\",\"multi\":false,\"name\":\"workload\",\"options\":[],\"query\":\"query_result((sum(istio_requests_total{destination_workload_namespace=~\\\"$namespace\\\"})
+ by (destination_workload) or sum(istio_requests_total{source_workload_namespace=~\\\"$namespace\\\"})
+ by (source_workload)) or (sum(istio_tcp_sent_bytes_total{destination_workload_namespace=~\\\"$namespace\\\"})
+ by (destination_workload) or sum(istio_tcp_sent_bytes_total{source_workload_namespace=~\\\"$namespace\\\"})
+ by (source_workload)))\",\"refresh\":1,\"regex\":\"/.*workload=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":1,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{\"selected\":true,\"text\":\"destination\",\"value\":\"destination\"},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":false,\"label\":\"Reporter\",\"multi\":true,\"name\":\"qrep\",\"query\":\"source,destination\",\"refresh\":1,\"regex\":\"\",\"skipUrlSync\":false,\"sort\":2,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"custom\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Inbound
+ Workload Namespace\",\"multi\":true,\"name\":\"srcns\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=~\\\"$qrep\\\",
+ destination_workload=\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\"})
+ by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+ destination_workload=\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\"})
+ by (source_workload_namespace))\",\"refresh\":1,\"regex\":\"/.*namespace=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":2,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Inbound
+ Workload\",\"multi\":true,\"name\":\"srcwl\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=~\\\"$qrep\\\",
+ destination_workload=\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=~\\\"$qrep\\\",
+ destination_workload=\\\"$workload\\\", destination_workload_namespace=~\\\"$namespace\\\",
+ source_workload_namespace=~\\\"$srcns\\\"}) by (source_workload))\",\"refresh\":1,\"regex\":\"/.*workload=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":3,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false},{\"allValue\":null,\"current\":{},\"datasource\":\"Prometheus\",\"definition\":\"\",\"hide\":0,\"includeAll\":true,\"label\":\"Destination
+ Service\",\"multi\":true,\"name\":\"dstsvc\",\"options\":[],\"query\":\"query_result(sum(istio_requests_total{reporter=\\\"source\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\"})
+ by (destination_service) or sum(istio_tcp_sent_bytes_total{reporter=\\\"source\\\",
+ source_workload=~\\\"$workload\\\", source_workload_namespace=~\\\"$namespace\\\"})
+ by (destination_service))\",\"refresh\":1,\"regex\":\"/.*destination_service=\\\"([^\\\"]*).*/\",\"skipUrlSync\":false,\"sort\":4,\"tagValuesQuery\":\"\",\"tags\":[],\"tagsQuery\":\"\",\"type\":\"query\",\"useTags\":false}]},\"time\":{\"from\":\"now-5m\",\"to\":\"now\"},\"timepicker\":{\"refresh_intervals\":[\"5m\",\"15m\",\"30m\",\"1h\",\"2h\",\"1d\"],\"time_options\":[\"5m\",\"15m\",\"1h\",\"6h\",\"12h\",\"24h\",\"2d\",\"7d\",\"30d\"]},\"timezone\":\"\",\"title\":\"Istio
+ Workload Dashboard\",\"uid\":\"UbsSZTDik\",\"version\":1}\n"
+kind: ConfigMap
+metadata:
+ creationTimestamp: null
+ name: istio-services-grafana-dashboards
+ namespace: istio-system
diff --git a/Istio-Samples/addons/jaeger.yaml b/Istio-Samples/addons/jaeger.yaml
new file mode 100644
index 00000000..0fc2a491
--- /dev/null
+++ b/Istio-Samples/addons/jaeger.yaml
@@ -0,0 +1,121 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: jaeger
+ namespace: istio-system
+ labels:
+ app: jaeger
+spec:
+ selector:
+ matchLabels:
+ app: jaeger
+ template:
+ metadata:
+ labels:
+ app: jaeger
+ sidecar.istio.io/inject: "false"
+ annotations:
+ prometheus.io/scrape: "true"
+ prometheus.io/port: "14269"
+ spec:
+ containers:
+ - name: jaeger
+ image: "docker.io/jaegertracing/all-in-one:1.46"
+ env:
+ - name: BADGER_EPHEMERAL
+ value: "false"
+ - name: SPAN_STORAGE_TYPE
+ value: "badger"
+ - name: BADGER_DIRECTORY_VALUE
+ value: "/badger/data"
+ - name: BADGER_DIRECTORY_KEY
+ value: "/badger/key"
+ - name: COLLECTOR_ZIPKIN_HOST_PORT
+ value: ":9411"
+ - name: MEMORY_MAX_TRACES
+ value: "50000"
+ - name: QUERY_BASE_PATH
+ value: /jaeger
+ livenessProbe:
+ httpGet:
+ path: /
+ port: 14269
+ readinessProbe:
+ httpGet:
+ path: /
+ port: 14269
+ volumeMounts:
+ - name: data
+ mountPath: /badger
+ resources:
+ requests:
+ cpu: 10m
+ volumes:
+ - name: data
+ emptyDir: {}
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: tracing
+ namespace: istio-system
+ labels:
+ app: jaeger
+spec:
+ type: ClusterIP
+ ports:
+ - name: http-query
+ port: 80
+ protocol: TCP
+ targetPort: 16686
+ # Note: Change port name if you add '--query.grpc.tls.enabled=true'
+ - name: grpc-query
+ port: 16685
+ protocol: TCP
+ targetPort: 16685
+ selector:
+ app: jaeger
+---
+# Jaeger implements the Zipkin API. To support swapping out the tracing backend, we use a Service named Zipkin.
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ name: zipkin
+ name: zipkin
+ namespace: istio-system
+spec:
+ ports:
+ - port: 9411
+ targetPort: 9411
+ name: http-query
+ selector:
+ app: jaeger
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: jaeger-collector
+ namespace: istio-system
+ labels:
+ app: jaeger
+spec:
+ type: ClusterIP
+ ports:
+ - name: jaeger-collector-http
+ port: 14268
+ targetPort: 14268
+ protocol: TCP
+ - name: jaeger-collector-grpc
+ port: 14250
+ targetPort: 14250
+ protocol: TCP
+ - port: 9411
+ targetPort: 9411
+ name: http-zipkin
+ - port: 4317
+ name: grpc-otel
+ - port: 4318
+ name: http-otel
+ selector:
+ app: jaeger
diff --git a/Istio-Samples/addons/kiali.yaml b/Istio-Samples/addons/kiali.yaml
new file mode 100644
index 00000000..7420d17f
--- /dev/null
+++ b/Istio-Samples/addons/kiali.yaml
@@ -0,0 +1,551 @@
+---
+# Source: kiali-server/templates/serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: kiali
+ namespace: istio-system
+ labels:
+ helm.sh/chart: kiali-server-1.76.0
+ app: kiali
+ app.kubernetes.io/name: kiali
+ app.kubernetes.io/instance: kiali
+ version: "v1.76.0"
+ app.kubernetes.io/version: "v1.76.0"
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: "kiali"
+...
+---
+# Source: kiali-server/templates/configmap.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: kiali
+ namespace: istio-system
+ labels:
+ helm.sh/chart: kiali-server-1.76.0
+ app: kiali
+ app.kubernetes.io/name: kiali
+ app.kubernetes.io/instance: kiali
+ version: "v1.76.0"
+ app.kubernetes.io/version: "v1.76.0"
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: "kiali"
+data:
+ config.yaml: |
+ auth:
+ openid: {}
+ openshift:
+ client_id_prefix: kiali
+ strategy: anonymous
+ deployment:
+ accessible_namespaces:
+ - '**'
+ additional_service_yaml: {}
+ affinity:
+ node: {}
+ pod: {}
+ pod_anti: {}
+ configmap_annotations: {}
+ custom_secrets: []
+ host_aliases: []
+ hpa:
+ api_version: autoscaling/v2beta2
+ spec: {}
+ image_digest: ""
+ image_name: quay.io/kiali/kiali
+ image_pull_policy: Always
+ image_pull_secrets: []
+ image_version: v1.76
+ ingress:
+ additional_labels: {}
+ class_name: nginx
+ override_yaml:
+ metadata: {}
+ ingress_enabled: false
+ instance_name: kiali
+ logger:
+ log_format: text
+ log_level: info
+ sampler_rate: "1"
+ time_field_format: 2006-01-02T15:04:05Z07:00
+ namespace: istio-system
+ node_selector: {}
+ pod_annotations: {}
+ pod_labels:
+ sidecar.istio.io/inject: "false"
+ priority_class_name: ""
+ replicas: 1
+ resources:
+ limits:
+ memory: 1Gi
+ requests:
+ cpu: 10m
+ memory: 64Mi
+ secret_name: kiali
+ security_context: {}
+ service_annotations: {}
+ service_type: ""
+ tolerations: []
+ version_label: v1.76.0
+ view_only_mode: false
+ external_services:
+ custom_dashboards:
+ enabled: true
+ istio:
+ root_namespace: istio-system
+ identity:
+ cert_file: ""
+ private_key_file: ""
+ istio_namespace: istio-system
+ kiali_feature_flags:
+ certificates_information_indicators:
+ enabled: true
+ secrets:
+ - cacerts
+ - istio-ca-secret
+ clustering:
+ autodetect_secrets:
+ enabled: true
+ label: kiali.io/multiCluster=true
+ clusters: []
+ disabled_features: []
+ validations:
+ ignore:
+ - KIA1301
+ login_token:
+ signing_key: CHANGEME00000000
+ server:
+ metrics_enabled: true
+ metrics_port: 9090
+ port: 20001
+ web_root: /kiali
+...
+---
+# Source: kiali-server/templates/role-viewer.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: kiali-viewer
+ labels:
+ helm.sh/chart: kiali-server-1.76.0
+ app: kiali
+ app.kubernetes.io/name: kiali
+ app.kubernetes.io/instance: kiali
+ version: "v1.76.0"
+ app.kubernetes.io/version: "v1.76.0"
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: "kiali"
+rules:
+- apiGroups: [""]
+ resources:
+ - configmaps
+ - endpoints
+ - pods/log
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups: [""]
+ resources:
+ - namespaces
+ - pods
+ - replicationcontrollers
+ - services
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups: [""]
+ resources:
+ - pods/portforward
+ verbs:
+ - create
+ - post
+- apiGroups: ["extensions", "apps"]
+ resources:
+ - daemonsets
+ - deployments
+ - replicasets
+ - statefulsets
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups: ["batch"]
+ resources:
+ - cronjobs
+ - jobs
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups:
+ - networking.istio.io
+ - security.istio.io
+ - extensions.istio.io
+ - telemetry.istio.io
+ - gateway.networking.k8s.io
+ resources: ["*"]
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups: ["apps.openshift.io"]
+ resources:
+ - deploymentconfigs
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups: ["project.openshift.io"]
+ resources:
+ - projects
+ verbs:
+ - get
+- apiGroups: ["route.openshift.io"]
+ resources:
+ - routes
+ verbs:
+ - get
+- apiGroups: ["authentication.k8s.io"]
+ resources:
+ - tokenreviews
+ verbs:
+ - create
+...
+---
+# Source: kiali-server/templates/role.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: kiali
+ labels:
+ helm.sh/chart: kiali-server-1.76.0
+ app: kiali
+ app.kubernetes.io/name: kiali
+ app.kubernetes.io/instance: kiali
+ version: "v1.76.0"
+ app.kubernetes.io/version: "v1.76.0"
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: "kiali"
+rules:
+- apiGroups: [""]
+ resources:
+ - configmaps
+ - endpoints
+ - pods/log
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups: [""]
+ resources:
+ - namespaces
+ - pods
+ - replicationcontrollers
+ - services
+ verbs:
+ - get
+ - list
+ - watch
+ - patch
+- apiGroups: [""]
+ resources:
+ - pods/portforward
+ verbs:
+ - create
+ - post
+- apiGroups: ["extensions", "apps"]
+ resources:
+ - daemonsets
+ - deployments
+ - replicasets
+ - statefulsets
+ verbs:
+ - get
+ - list
+ - watch
+ - patch
+- apiGroups: ["batch"]
+ resources:
+ - cronjobs
+ - jobs
+ verbs:
+ - get
+ - list
+ - watch
+ - patch
+- apiGroups:
+ - networking.istio.io
+ - security.istio.io
+ - extensions.istio.io
+ - telemetry.istio.io
+ - gateway.networking.k8s.io
+ resources: ["*"]
+ verbs:
+ - get
+ - list
+ - watch
+ - create
+ - delete
+ - patch
+- apiGroups: ["apps.openshift.io"]
+ resources:
+ - deploymentconfigs
+ verbs:
+ - get
+ - list
+ - watch
+ - patch
+- apiGroups: ["project.openshift.io"]
+ resources:
+ - projects
+ verbs:
+ - get
+- apiGroups: ["route.openshift.io"]
+ resources:
+ - routes
+ verbs:
+ - get
+- apiGroups: ["authentication.k8s.io"]
+ resources:
+ - tokenreviews
+ verbs:
+ - create
+...
+---
+# Source: kiali-server/templates/rolebinding.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: kiali
+ labels:
+ helm.sh/chart: kiali-server-1.76.0
+ app: kiali
+ app.kubernetes.io/name: kiali
+ app.kubernetes.io/instance: kiali
+ version: "v1.76.0"
+ app.kubernetes.io/version: "v1.76.0"
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: "kiali"
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: kiali
+subjects:
+- kind: ServiceAccount
+ name: kiali
+ namespace: istio-system
+...
+---
+# Source: kiali-server/templates/role-controlplane.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: kiali-controlplane
+ namespace: istio-system
+ labels:
+ helm.sh/chart: kiali-server-1.76.0
+ app: kiali
+ app.kubernetes.io/name: kiali
+ app.kubernetes.io/instance: kiali
+ version: "v1.76.0"
+ app.kubernetes.io/version: "v1.76.0"
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: "kiali"
+rules:
+- apiGroups: [""]
+ resourceNames:
+ - cacerts
+ - istio-ca-secret
+ resources:
+ - secrets
+ verbs:
+ - get
+ - list
+ - watch
+...
+---
+# Source: kiali-server/templates/rolebinding-controlplane.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: kiali-controlplane
+ namespace: istio-system
+ labels:
+ helm.sh/chart: kiali-server-1.76.0
+ app: kiali
+ app.kubernetes.io/name: kiali
+ app.kubernetes.io/instance: kiali
+ version: "v1.76.0"
+ app.kubernetes.io/version: "v1.76.0"
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: "kiali"
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: kiali-controlplane
+subjects:
+- kind: ServiceAccount
+ name: kiali
+ namespace: istio-system
+...
+---
+# Source: kiali-server/templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: kiali
+ namespace: istio-system
+ labels:
+ helm.sh/chart: kiali-server-1.76.0
+ app: kiali
+ app.kubernetes.io/name: kiali
+ app.kubernetes.io/instance: kiali
+ version: "v1.76.0"
+ app.kubernetes.io/version: "v1.76.0"
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: "kiali"
+ annotations:
+spec:
+ ports:
+ - name: http
+ appProtocol: http
+ protocol: TCP
+ port: 20001
+ - name: http-metrics
+ appProtocol: http
+ protocol: TCP
+ port: 9090
+ selector:
+ app.kubernetes.io/name: kiali
+ app.kubernetes.io/instance: kiali
+...
+---
+# Source: kiali-server/templates/deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: kiali
+ namespace: istio-system
+ labels:
+ helm.sh/chart: kiali-server-1.76.0
+ app: kiali
+ app.kubernetes.io/name: kiali
+ app.kubernetes.io/instance: kiali
+ version: "v1.76.0"
+ app.kubernetes.io/version: "v1.76.0"
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: "kiali"
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: kiali
+ app.kubernetes.io/instance: kiali
+ strategy:
+ rollingUpdate:
+ maxSurge: 1
+ maxUnavailable: 1
+ type: RollingUpdate
+ template:
+ metadata:
+ name: kiali
+ labels:
+ helm.sh/chart: kiali-server-1.76.0
+ app: kiali
+ app.kubernetes.io/name: kiali
+ app.kubernetes.io/instance: kiali
+ version: "v1.76.0"
+ app.kubernetes.io/version: "v1.76.0"
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: "kiali"
+ sidecar.istio.io/inject: "false"
+ annotations:
+ checksum/config: aebd819b94172ef9b148702b7bb438ac35bd1eb284bbb9b13769d8576374fbda
+ prometheus.io/scrape: "true"
+ prometheus.io/port: "9090"
+ kiali.io/dashboards: go,kiali
+ spec:
+ serviceAccountName: kiali
+ containers:
+ - image: "quay.io/kiali/kiali:v1.76"
+ imagePullPolicy: Always
+ name: kiali
+ command:
+ - "/opt/kiali/kiali"
+ - "-config"
+ - "/kiali-configuration/config.yaml"
+ securityContext:
+ allowPrivilegeEscalation: false
+ privileged: false
+ readOnlyRootFilesystem: true
+ runAsNonRoot: true
+ capabilities:
+ drop:
+ - ALL
+ ports:
+ - name: api-port
+ containerPort: 20001
+ - name: http-metrics
+ containerPort: 9090
+ readinessProbe:
+ httpGet:
+ path: /kiali/healthz
+ port: api-port
+ scheme: HTTP
+ initialDelaySeconds: 5
+ periodSeconds: 30
+ livenessProbe:
+ httpGet:
+ path: /kiali/healthz
+ port: api-port
+ scheme: HTTP
+ initialDelaySeconds: 5
+ periodSeconds: 30
+ env:
+ - name: ACTIVE_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ - name: LOG_LEVEL
+ value: "info"
+ - name: LOG_FORMAT
+ value: "text"
+ - name: LOG_TIME_FIELD_FORMAT
+ value: "2006-01-02T15:04:05Z07:00"
+ - name: LOG_SAMPLER_RATE
+ value: "1"
+ volumeMounts:
+ - name: kiali-configuration
+ mountPath: "/kiali-configuration"
+ - name: kiali-cert
+ mountPath: "/kiali-cert"
+ - name: kiali-secret
+ mountPath: "/kiali-secret"
+ - name: kiali-cabundle
+ mountPath: "/kiali-cabundle"
+ resources:
+ limits:
+ memory: 1Gi
+ requests:
+ cpu: 10m
+ memory: 64Mi
+ volumes:
+ - name: kiali-configuration
+ configMap:
+ name: kiali
+ - name: kiali-cert
+ secret:
+ secretName: istio.kiali-service-account
+ optional: true
+ - name: kiali-secret
+ secret:
+ secretName: kiali
+ optional: true
+ - name: kiali-cabundle
+ configMap:
+ name: kiali-cabundle
+ optional: true
+...
diff --git a/Istio-Samples/addons/loki.yaml b/Istio-Samples/addons/loki.yaml
new file mode 100644
index 00000000..edabc36a
--- /dev/null
+++ b/Istio-Samples/addons/loki.yaml
@@ -0,0 +1,283 @@
+---
+# Source: loki/templates/serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: loki
+ labels:
+ helm.sh/chart: loki-4.8.0
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+ app.kubernetes.io/version: "2.7.3"
+ app.kubernetes.io/managed-by: Helm
+automountServiceAccountToken: true
+---
+# Source: loki/templates/configmap.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: loki
+ labels:
+ helm.sh/chart: loki-4.8.0
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+ app.kubernetes.io/version: "2.7.3"
+ app.kubernetes.io/managed-by: Helm
+data:
+ config.yaml: |
+ auth_enabled: false
+ common:
+ compactor_address: 'loki'
+ path_prefix: /var/loki
+ replication_factor: 1
+ storage:
+ filesystem:
+ chunks_directory: /var/loki/chunks
+ rules_directory: /var/loki/rules
+ limits_config:
+ enforce_metric_name: false
+ max_cache_freshness_per_query: 10m
+ reject_old_samples: true
+ reject_old_samples_max_age: 168h
+ split_queries_by_interval: 15m
+ memberlist:
+ join_members:
+ - loki-memberlist
+ query_range:
+ align_queries_with_step: true
+ ruler:
+ storage:
+ type: local
+ runtime_config:
+ file: /etc/loki/runtime-config/runtime-config.yaml
+ schema_config:
+ configs:
+ - from: "2022-01-11"
+ index:
+ period: 24h
+ prefix: loki_index_
+ object_store: filesystem
+ schema: v12
+ store: boltdb-shipper
+ server:
+ grpc_listen_port: 9095
+ http_listen_port: 3100
+ storage_config:
+ hedging:
+ at: 250ms
+ max_per_second: 20
+ up_to: 3
+ table_manager:
+ retention_deletes_enabled: false
+ retention_period: 0
+---
+# Source: loki/templates/runtime-configmap.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: loki-runtime
+ labels:
+ helm.sh/chart: loki-4.8.0
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+ app.kubernetes.io/version: "2.7.3"
+ app.kubernetes.io/managed-by: Helm
+data:
+ runtime-config.yaml: |
+
+ {}
+---
+# Source: loki/templates/service-memberlist.yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: loki-memberlist
+ labels:
+ helm.sh/chart: loki-4.8.0
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+ app.kubernetes.io/version: "2.7.3"
+ app.kubernetes.io/managed-by: Helm
+spec:
+ type: ClusterIP
+ clusterIP: None
+ ports:
+ - name: tcp
+ port: 7946
+ targetPort: http-memberlist
+ protocol: TCP
+ selector:
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+ app.kubernetes.io/part-of: memberlist
+---
+# Source: loki/templates/single-binary/service-headless.yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: loki-headless
+ namespace: istio-system
+ labels:
+ helm.sh/chart: loki-4.8.0
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+ app.kubernetes.io/version: "2.7.3"
+ app.kubernetes.io/managed-by: Helm
+ variant: headless
+ prometheus.io/service-monitor: "false"
+spec:
+ clusterIP: None
+ ports:
+ - name: http-metrics
+ port: 3100
+ targetPort: http-metrics
+ protocol: TCP
+ selector:
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+---
+# Source: loki/templates/single-binary/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: loki
+ labels:
+ helm.sh/chart: loki-4.8.0
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+ app.kubernetes.io/version: "2.7.3"
+ app.kubernetes.io/managed-by: Helm
+spec:
+ type: ClusterIP
+ ports:
+ - name: http-metrics
+ port: 3100
+ targetPort: http-metrics
+ protocol: TCP
+ - name: grpc
+ port: 9095
+ targetPort: grpc
+ protocol: TCP
+ selector:
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+ app.kubernetes.io/component: single-binary
+---
+# Source: loki/templates/single-binary/statefulset.yaml
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: loki
+ labels:
+ helm.sh/chart: loki-4.8.0
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+ app.kubernetes.io/version: "2.7.3"
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/component: single-binary
+ app.kubernetes.io/part-of: memberlist
+spec:
+ replicas: 1
+ podManagementPolicy: Parallel
+ updateStrategy:
+ rollingUpdate:
+ partition: 0
+ serviceName: loki-headless
+ revisionHistoryLimit: 10
+
+ persistentVolumeClaimRetentionPolicy:
+ whenDeleted: Delete
+ whenScaled: Delete
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+ app.kubernetes.io/component: single-binary
+ template:
+ metadata:
+ annotations:
+ checksum/config: a9239b6352e34bbfc748669ed46cb24211fc3491ee7f2c6381af805f8f08fe29
+ labels:
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+ app.kubernetes.io/component: single-binary
+ app.kubernetes.io/part-of: memberlist
+ spec:
+ serviceAccountName: loki
+ automountServiceAccountToken: true
+ enableServiceLinks: true
+
+ securityContext:
+ fsGroup: 10001
+ runAsGroup: 10001
+ runAsNonRoot: true
+ runAsUser: 10001
+ terminationGracePeriodSeconds: 30
+ containers:
+ - name: loki
+ image: docker.io/grafana/loki:2.7.3
+ imagePullPolicy: IfNotPresent
+ args:
+ - -config.file=/etc/loki/config/config.yaml
+ - -target=all
+ ports:
+ - name: http-metrics
+ containerPort: 3100
+ protocol: TCP
+ - name: grpc
+ containerPort: 9095
+ protocol: TCP
+ - name: http-memberlist
+ containerPort: 7946
+ protocol: TCP
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ readOnlyRootFilesystem: true
+ readinessProbe:
+ httpGet:
+ path: /ready
+ port: http-metrics
+ initialDelaySeconds: 30
+ timeoutSeconds: 1
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: config
+ mountPath: /etc/loki/config
+ - name: runtime-config
+ mountPath: /etc/loki/runtime-config
+ - name: storage
+ mountPath: /var/loki
+ resources:
+ {}
+ affinity:
+ podAntiAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ - labelSelector:
+ matchLabels:
+ app.kubernetes.io/name: loki
+ app.kubernetes.io/instance: loki
+ app.kubernetes.io/component: single-binary
+ topologyKey: kubernetes.io/hostname
+
+ volumes:
+ - name: tmp
+ emptyDir: {}
+ - name: config
+ configMap:
+ name: loki
+ - name: runtime-config
+ configMap:
+ name: loki-runtime
+ volumeClaimTemplates:
+ - metadata:
+ name: storage
+ spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: "10Gi"
diff --git a/Istio-Samples/addons/prometheus.yaml b/Istio-Samples/addons/prometheus.yaml
new file mode 100644
index 00000000..e4bd3363
--- /dev/null
+++ b/Istio-Samples/addons/prometheus.yaml
@@ -0,0 +1,553 @@
+---
+# Source: prometheus/templates/serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ labels:
+ app.kubernetes.io/component: server
+ app.kubernetes.io/name: prometheus
+ app.kubernetes.io/instance: prometheus
+ app.kubernetes.io/version: v2.48.0
+ helm.sh/chart: prometheus-25.8.0
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: prometheus
+ name: prometheus
+ namespace: istio-system
+ annotations:
+ {}
+---
+# Source: prometheus/templates/cm.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ labels:
+ app.kubernetes.io/component: server
+ app.kubernetes.io/name: prometheus
+ app.kubernetes.io/instance: prometheus
+ app.kubernetes.io/version: v2.48.0
+ helm.sh/chart: prometheus-25.8.0
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: prometheus
+ name: prometheus
+ namespace: istio-system
+data:
+ allow-snippet-annotations: "false"
+ alerting_rules.yml: |
+ {}
+ alerts: |
+ {}
+ prometheus.yml: |
+ global:
+ evaluation_interval: 1m
+ scrape_interval: 15s
+ scrape_timeout: 10s
+ rule_files:
+ - /etc/config/recording_rules.yml
+ - /etc/config/alerting_rules.yml
+ - /etc/config/rules
+ - /etc/config/alerts
+ scrape_configs:
+ - job_name: prometheus
+ static_configs:
+ - targets:
+ - localhost:9090
+ - bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
+ job_name: kubernetes-apiservers
+ kubernetes_sd_configs:
+ - role: endpoints
+ relabel_configs:
+ - action: keep
+ regex: default;kubernetes;https
+ source_labels:
+ - __meta_kubernetes_namespace
+ - __meta_kubernetes_service_name
+ - __meta_kubernetes_endpoint_port_name
+ scheme: https
+ tls_config:
+ ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ insecure_skip_verify: true
+ - bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
+ job_name: kubernetes-nodes
+ kubernetes_sd_configs:
+ - role: node
+ relabel_configs:
+ - action: labelmap
+ regex: __meta_kubernetes_node_label_(.+)
+ - replacement: kubernetes.default.svc:443
+ target_label: __address__
+ - regex: (.+)
+ replacement: /api/v1/nodes/$1/proxy/metrics
+ source_labels:
+ - __meta_kubernetes_node_name
+ target_label: __metrics_path__
+ scheme: https
+ tls_config:
+ ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ insecure_skip_verify: true
+ - bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
+ job_name: kubernetes-nodes-cadvisor
+ kubernetes_sd_configs:
+ - role: node
+ relabel_configs:
+ - action: labelmap
+ regex: __meta_kubernetes_node_label_(.+)
+ - replacement: kubernetes.default.svc:443
+ target_label: __address__
+ - regex: (.+)
+ replacement: /api/v1/nodes/$1/proxy/metrics/cadvisor
+ source_labels:
+ - __meta_kubernetes_node_name
+ target_label: __metrics_path__
+ scheme: https
+ tls_config:
+ ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ insecure_skip_verify: true
+ - honor_labels: true
+ job_name: kubernetes-service-endpoints
+ kubernetes_sd_configs:
+ - role: endpoints
+ relabel_configs:
+ - action: keep
+ regex: true
+ source_labels:
+ - __meta_kubernetes_service_annotation_prometheus_io_scrape
+ - action: drop
+ regex: true
+ source_labels:
+ - __meta_kubernetes_service_annotation_prometheus_io_scrape_slow
+ - action: replace
+ regex: (https?)
+ source_labels:
+ - __meta_kubernetes_service_annotation_prometheus_io_scheme
+ target_label: __scheme__
+ - action: replace
+ regex: (.+)
+ source_labels:
+ - __meta_kubernetes_service_annotation_prometheus_io_path
+ target_label: __metrics_path__
+ - action: replace
+ regex: (.+?)(?::\d+)?;(\d+)
+ replacement: $1:$2
+ source_labels:
+ - __address__
+ - __meta_kubernetes_service_annotation_prometheus_io_port
+ target_label: __address__
+ - action: labelmap
+ regex: __meta_kubernetes_service_annotation_prometheus_io_param_(.+)
+ replacement: __param_$1
+ - action: labelmap
+ regex: __meta_kubernetes_service_label_(.+)
+ - action: replace
+ source_labels:
+ - __meta_kubernetes_namespace
+ target_label: namespace
+ - action: replace
+ source_labels:
+ - __meta_kubernetes_service_name
+ target_label: service
+ - action: replace
+ source_labels:
+ - __meta_kubernetes_pod_node_name
+ target_label: node
+ - honor_labels: true
+ job_name: kubernetes-service-endpoints-slow
+ kubernetes_sd_configs:
+ - role: endpoints
+ relabel_configs:
+ - action: keep
+ regex: true
+ source_labels:
+ - __meta_kubernetes_service_annotation_prometheus_io_scrape_slow
+ - action: replace
+ regex: (https?)
+ source_labels:
+ - __meta_kubernetes_service_annotation_prometheus_io_scheme
+ target_label: __scheme__
+ - action: replace
+ regex: (.+)
+ source_labels:
+ - __meta_kubernetes_service_annotation_prometheus_io_path
+ target_label: __metrics_path__
+ - action: replace
+ regex: (.+?)(?::\d+)?;(\d+)
+ replacement: $1:$2
+ source_labels:
+ - __address__
+ - __meta_kubernetes_service_annotation_prometheus_io_port
+ target_label: __address__
+ - action: labelmap
+ regex: __meta_kubernetes_service_annotation_prometheus_io_param_(.+)
+ replacement: __param_$1
+ - action: labelmap
+ regex: __meta_kubernetes_service_label_(.+)
+ - action: replace
+ source_labels:
+ - __meta_kubernetes_namespace
+ target_label: namespace
+ - action: replace
+ source_labels:
+ - __meta_kubernetes_service_name
+ target_label: service
+ - action: replace
+ source_labels:
+ - __meta_kubernetes_pod_node_name
+ target_label: node
+ scrape_interval: 5m
+ scrape_timeout: 30s
+ - honor_labels: true
+ job_name: prometheus-pushgateway
+ kubernetes_sd_configs:
+ - role: service
+ relabel_configs:
+ - action: keep
+ regex: pushgateway
+ source_labels:
+ - __meta_kubernetes_service_annotation_prometheus_io_probe
+ - honor_labels: true
+ job_name: kubernetes-services
+ kubernetes_sd_configs:
+ - role: service
+ metrics_path: /probe
+ params:
+ module:
+ - http_2xx
+ relabel_configs:
+ - action: keep
+ regex: true
+ source_labels:
+ - __meta_kubernetes_service_annotation_prometheus_io_probe
+ - source_labels:
+ - __address__
+ target_label: __param_target
+ - replacement: blackbox
+ target_label: __address__
+ - source_labels:
+ - __param_target
+ target_label: instance
+ - action: labelmap
+ regex: __meta_kubernetes_service_label_(.+)
+ - source_labels:
+ - __meta_kubernetes_namespace
+ target_label: namespace
+ - source_labels:
+ - __meta_kubernetes_service_name
+ target_label: service
+ - honor_labels: true
+ job_name: kubernetes-pods
+ kubernetes_sd_configs:
+ - role: pod
+ relabel_configs:
+ - action: keep
+ regex: true
+ source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_scrape
+ - action: drop
+ regex: true
+ source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_scrape_slow
+ - action: replace
+ regex: (https?)
+ source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_scheme
+ target_label: __scheme__
+ - action: replace
+ regex: (.+)
+ source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_path
+ target_label: __metrics_path__
+ - action: replace
+ regex: (\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})
+ replacement: '[$2]:$1'
+ source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_port
+ - __meta_kubernetes_pod_ip
+ target_label: __address__
+ - action: replace
+ regex: (\d+);((([0-9]+?)(\.|$)){4})
+ replacement: $2:$1
+ source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_port
+ - __meta_kubernetes_pod_ip
+ target_label: __address__
+ - action: labelmap
+ regex: __meta_kubernetes_pod_annotation_prometheus_io_param_(.+)
+ replacement: __param_$1
+ - action: labelmap
+ regex: __meta_kubernetes_pod_label_(.+)
+ - action: replace
+ source_labels:
+ - __meta_kubernetes_namespace
+ target_label: namespace
+ - action: replace
+ source_labels:
+ - __meta_kubernetes_pod_name
+ target_label: pod
+ - action: drop
+ regex: Pending|Succeeded|Failed|Completed
+ source_labels:
+ - __meta_kubernetes_pod_phase
+ - action: replace
+ source_labels:
+ - __meta_kubernetes_pod_node_name
+ target_label: node
+ - honor_labels: true
+ job_name: kubernetes-pods-slow
+ kubernetes_sd_configs:
+ - role: pod
+ relabel_configs:
+ - action: keep
+ regex: true
+ source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_scrape_slow
+ - action: replace
+ regex: (https?)
+ source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_scheme
+ target_label: __scheme__
+ - action: replace
+ regex: (.+)
+ source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_path
+ target_label: __metrics_path__
+ - action: replace
+ regex: (\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})
+ replacement: '[$2]:$1'
+ source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_port
+ - __meta_kubernetes_pod_ip
+ target_label: __address__
+ - action: replace
+ regex: (\d+);((([0-9]+?)(\.|$)){4})
+ replacement: $2:$1
+ source_labels:
+ - __meta_kubernetes_pod_annotation_prometheus_io_port
+ - __meta_kubernetes_pod_ip
+ target_label: __address__
+ - action: labelmap
+ regex: __meta_kubernetes_pod_annotation_prometheus_io_param_(.+)
+ replacement: __param_$1
+ - action: labelmap
+ regex: __meta_kubernetes_pod_label_(.+)
+ - action: replace
+ source_labels:
+ - __meta_kubernetes_namespace
+ target_label: namespace
+ - action: replace
+ source_labels:
+ - __meta_kubernetes_pod_name
+ target_label: pod
+ - action: drop
+ regex: Pending|Succeeded|Failed|Completed
+ source_labels:
+ - __meta_kubernetes_pod_phase
+ - action: replace
+ source_labels:
+ - __meta_kubernetes_pod_node_name
+ target_label: node
+ scrape_interval: 5m
+ scrape_timeout: 30s
+ recording_rules.yml: |
+ {}
+ rules: |
+ {}
+---
+# Source: prometheus/templates/clusterrole.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ labels:
+ app.kubernetes.io/component: server
+ app.kubernetes.io/name: prometheus
+ app.kubernetes.io/instance: prometheus
+ app.kubernetes.io/version: v2.48.0
+ helm.sh/chart: prometheus-25.8.0
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: prometheus
+ name: prometheus
+rules:
+ - apiGroups:
+ - ""
+ resources:
+ - nodes
+ - nodes/proxy
+ - nodes/metrics
+ - services
+ - endpoints
+ - pods
+ - ingresses
+ - configmaps
+ verbs:
+ - get
+ - list
+ - watch
+ - apiGroups:
+ - "extensions"
+ - "networking.k8s.io"
+ resources:
+ - ingresses/status
+ - ingresses
+ verbs:
+ - get
+ - list
+ - watch
+ - apiGroups:
+ - "discovery.k8s.io"
+ resources:
+ - endpointslices
+ verbs:
+ - get
+ - list
+ - watch
+ - nonResourceURLs:
+ - "/metrics"
+ verbs:
+ - get
+---
+# Source: prometheus/templates/clusterrolebinding.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ labels:
+ app.kubernetes.io/component: server
+ app.kubernetes.io/name: prometheus
+ app.kubernetes.io/instance: prometheus
+ app.kubernetes.io/version: v2.48.0
+ helm.sh/chart: prometheus-25.8.0
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: prometheus
+ name: prometheus
+subjects:
+ - kind: ServiceAccount
+ name: prometheus
+ namespace: istio-system
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: prometheus
+---
+# Source: prometheus/templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ app.kubernetes.io/component: server
+ app.kubernetes.io/name: prometheus
+ app.kubernetes.io/instance: prometheus
+ app.kubernetes.io/version: v2.48.0
+ helm.sh/chart: prometheus-25.8.0
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: prometheus
+ name: prometheus
+ namespace: istio-system
+spec:
+ ports:
+ - name: http
+ port: 9090
+ protocol: TCP
+ targetPort: 9090
+ selector:
+ app.kubernetes.io/component: server
+ app.kubernetes.io/name: prometheus
+ app.kubernetes.io/instance: prometheus
+ sessionAffinity: None
+ type: "ClusterIP"
+---
+# Source: prometheus/templates/deploy.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app.kubernetes.io/component: server
+ app.kubernetes.io/name: prometheus
+ app.kubernetes.io/instance: prometheus
+ app.kubernetes.io/version: v2.48.0
+ helm.sh/chart: prometheus-25.8.0
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: prometheus
+ name: prometheus
+ namespace: istio-system
+spec:
+ selector:
+ matchLabels:
+ app.kubernetes.io/component: server
+ app.kubernetes.io/name: prometheus
+ app.kubernetes.io/instance: prometheus
+ replicas: 1
+ revisionHistoryLimit: 10
+ strategy:
+ type: Recreate
+ rollingUpdate: null
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/component: server
+ app.kubernetes.io/name: prometheus
+ app.kubernetes.io/instance: prometheus
+ app.kubernetes.io/version: v2.48.0
+ helm.sh/chart: prometheus-25.8.0
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/part-of: prometheus
+
+ sidecar.istio.io/inject: "false"
+ spec:
+ enableServiceLinks: true
+ serviceAccountName: prometheus
+ containers:
+ - name: prometheus-server-configmap-reload
+ image: "ghcr.io/prometheus-operator/prometheus-config-reloader:v0.67.0"
+ imagePullPolicy: "IfNotPresent"
+ args:
+ - --watched-dir=/etc/config
+ - --reload-url=http://127.0.0.1:9090/-/reload
+ volumeMounts:
+ - name: config-volume
+ mountPath: /etc/config
+ readOnly: true
+
+ - name: prometheus-server
+ image: "prom/prometheus:v2.48.0"
+ imagePullPolicy: "IfNotPresent"
+ args:
+ - --storage.tsdb.retention.time=15d
+ - --config.file=/etc/config/prometheus.yml
+ - --storage.tsdb.path=/data
+ - --web.console.libraries=/etc/prometheus/console_libraries
+ - --web.console.templates=/etc/prometheus/consoles
+ - --web.enable-lifecycle
+ ports:
+ - containerPort: 9090
+ readinessProbe:
+ httpGet:
+ path: /-/ready
+ port: 9090
+ scheme: HTTP
+ initialDelaySeconds: 0
+ periodSeconds: 5
+ timeoutSeconds: 4
+ failureThreshold: 3
+ successThreshold: 1
+ livenessProbe:
+ httpGet:
+ path: /-/healthy
+ port: 9090
+ scheme: HTTP
+ initialDelaySeconds: 30
+ periodSeconds: 15
+ timeoutSeconds: 10
+ failureThreshold: 3
+ successThreshold: 1
+ volumeMounts:
+ - name: config-volume
+ mountPath: /etc/config
+ - name: storage-volume
+ mountPath: /data
+ subPath: ""
+ dnsPolicy: ClusterFirst
+ terminationGracePeriodSeconds: 300
+ volumes:
+ - name: config-volume
+ configMap:
+ name: prometheus
+ - name: storage-volume
+ emptyDir:
+ {}
diff --git a/Istio-Samples/ambient-argo/README.md b/Istio-Samples/ambient-argo/README.md
new file mode 100644
index 00000000..9eb1024e
--- /dev/null
+++ b/Istio-Samples/ambient-argo/README.md
@@ -0,0 +1,99 @@
+# Ambient Reference Architecture w/ Argo
+
+This repo contains a reference architecture for operating Istio Ambient Mesh with ArgoCD using GitOps. It demonstrates best practices for leveraging Istio as part of an application platform.
+
+## :boom: DISCLAIMER
+
+Istio Ambient Mesh is still in Alpha, and is not suitable for production use. Likewise, this reference architecture is of Alpha quality, and includes several rough edges, including:
+ * Cluster-Scoped upgrades cause known traffic loss, and have wide blast radius.
+ * The tag chart is forked from the primary istio repo, and needs to be merged and published
+ * CRDs are not currently upgraded
+
+## Getting Started
+
+This reference architecture assumes that you have an ArgoCD installation with:
+ * A [connected cluster](https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_cluster/) named `ambient-cluster`
+ * A connection to your repository (for private repos)
+
+To deploy Istio, supporting software, and the bookinfo sample application, copy this folder to the root of your repo and run:
+
+```bash
+read -p 'Please enter the URL to your repo:'
+OLD_REPO='{repo-placeholder}'
+find . \( -type d -name .git -prune \) -o -type f -name '*.yaml' -print0 | xargs -0 sed -i s,$OLD_REPO,$NEW_REPO,g
+argocd create application -f meta-application.json
+```
+
+## Repository Layout
+
+The meta-application.yaml file is an App-of-Apps that references all other applications needed for running Istio and the demo application via ArgoCD. The diagram below demonstrates the deployment mechanism for each part of the platform.
+
+![architecture diagram][layout]
+
+## Principles
+
+The [GitOps Principles](https://opengitops.dev/) guide this reference architecture. With the exception of [./meta-application.yaml](./meta-application.yaml) (the bootstrap file), Git is the source of truth for all components of our application. Changes to all components of Istio, including the data plane, are initiated with a pull request. Likewise, rollbacks are as simple as a revert.
+
+In particular, Istio Sidecars are known to violate the Declarative principle - the version of Istio injected in the sidecar is determined at runtime by the version of the injector at the time the pod was created. Upgrading the injector does not cause the sidecar to upgrade, instead all injected pods must be restarted in order to upgrade their sidecars, which is an imperative operation, rather than a declarative one.
+
+Additionally, emerging patterns from the field of Platform Engineering guide our understanding of enterprise roles. In particular, two roles are represented in this Architecture: the Application Developer (AppDev) and Platform Engineer (PlatEng).
+
+### Role: Application Developer
+
+The AppDev is responsible for the development and delivery of their application, in this case the bookinfo e-commerce application. The AppDev will make use of Istio features, such as HTTPRoutes, AuthorizationPolicy, and L4-L7 telemetry, but is not an expert in Istio, and should be unaware of installation and upgrades. In most cases, AppDev's use of Istio APIs is both templated, to provide them with a simpler API surface, and limited by Policy with tools such as Gatekeeper. Because the focus of this architecture, these technologies are not included here.
+
+### Role: Platform Engineer
+
+The PlatEng is responsible for providing the AppDev with a comprehensive application platform, which simplifies getting the application from Source Control to Production, as well as operating the App in Production. As such, the PlatEng team must have a good deal of expertise in installing, operating, and automating a broad array of Cloud Native technologies, such as Service Mesh, Kubernetes, Observability stores and consumers, GitOps tooling, Policy enforcement, and templating tools such as Crossplane. Due to this breadth, the Platform Engineer cannot spend all their time learning or operating any one technology, and any technology that is too difficult to operate is likely to be removed from the platform.
+
+## Components
+
+Istio is composed of six charts in Ambient Mode. The components are divided between the Control Plane and the Data Plane, and some are Cluster-Scoped, while others can have multiple versions in a single cluster.
+
+| | Control Plane | Data Plane |
+| ------------------- |:--------------------------:| :----------------:|
+| **Cluster-Scoped** | CRDs + validation | CNI ztunnel |
+| **Workload-Scoped** | istiod tags + revisions | waypoint (envoy) |
+
+Of these components, only waypoints (and other gateways) are intended to be operated by the AppDev (some users may choose to limit ingress gateways to the PlatEng role as well). The remainder are the sole responsibility of the PlatEng role, and will be the focus of this reference architecture.
+
+### Tags and Revisions
+
+Istio components, particularly the waypoint, can specify which control plane they connect to (and by inference what version of the data plane they will run) using the `istio.io/rev` label set to a tag or revision.
+
+As in sidecar mode, every control plane installation may (and should) include a revision name, which is a stable identifier for that control plane installation and version. For simplicity, we recommend using the version of the control plane as the revision name (see [./istio/control-plane-appset.yaml:9](./istio/control-plane-appset.yaml), at .spec.generators[0].list.elements[*].revision).
+
+Tags also identify control planes, but unlike revisions, tags are mutable references to revisions. When an Istio Gateway (waypoint, ingress, or egress) references a particular tag, a dataplane is created using the version of the tag reference, and connects to the control plane indicated by the tag. In this way, gateways can be organized into channels, or distinct groups which will be upgraded concurrently, without any involvement from the AppDev who owns the gateway.
+
+In this reference architecture, three tags are used: stable, rapid, and default (the default tag will manage any gateways which do not use the `istio.io/rev` label). In the example application, we have included an ingress gateway on the default tag, and two waypoints for the reviews and details services, which use the rapid and stable tags. At the time of writing, the rapid revision points to revision 1-19-3, while the stable and default revisions point to revision 1-18-5. The tags definitions can be found at [./istio/tags.yaml](./istio/tags.yaml).
+
+## Upgrade Planning
+
+This reference architecture provides the tools to declaratively manage your Istio Ambient installations with simple pull requests. Before performing an upgrade, however, the PlatEng team should consider how they would like their upgrades to progress. The two most common strategies are channels and phases, and these strategies can be combined.
+
+In a phased model, there is generally a single version of Istio available in the cluster. When a new version becomes available, the phases are moved one at a time to the new version, in order, until all phases have upgraded to the new model. The phased model supports any number of phases based on the needs of your platform.
+
+In a channel model, multiple versions of Istio are available for use by application developers at any point in time, based on their requirements for risk profile and new features or bugfixes. For example, at the time of this writing, the stable tag or channel is using Istio 1.18.5, while the rapid channel is using Istio 1.19.3. Under the channel model, these versions would be updated in-place as new patch releases are produced for various bugs or security concerns. Then, when Istio 1.20.0 ships (ETA late November 2023), the rapid channel will be moved to point to version 1.20.0, while the stable version will be moved to point to 1.19.x (where x is the lates patch result at that time). Because Istio releases are supported until two subsequent minor versions are shipiped (ie 1.18 will be supported until several weeks after 1.20 ships), this reference architecture uses only two channels, though more are possible.
+
+![strategy diagram][strategies]
+
+The channel and phased strategies can be combined into a comprehensive (though somewhat complicated) model where each channel contains phases, which determine the order of rollouts within the channel.
+
+## Playbook: Minor Version Upgrade
+
+COMING SOON
+
+## Playbook: Major Version Upgrade
+
+COMING SOON
+
+## Tips and Tricks
+
+For a quick (but messy) readout on what Istio versions are being used in this repo, run:
+
+```bash
+yq '.spec.generators[0].list.elements' < istio/control-plane-appset.yaml && yq '.spec.source.helm.valuesObject.base.tags' < istio/tags.yaml && grep 'targetRevision' istio/*.yaml
+```
+
+[layout]: ./documentation/argo-reference-arch.svg "Repo Layout Diagram"
+[strategies]: ./documentation/Ambient%20Upgrade%20-%20Strategies.png "Upgrade Strategies Diagram"
diff --git a/Istio-Samples/ambient-argo/application/application.yaml b/Istio-Samples/ambient-argo/application/application.yaml
new file mode 100644
index 00000000..91eaea00
--- /dev/null
+++ b/Istio-Samples/ambient-argo/application/application.yaml
@@ -0,0 +1,22 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ name: bookinfo-application
+ namespace: argocd
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+spec:
+ destination:
+ name: ambient-cluster
+ namespace: ambient
+ source:
+ path: application
+ repoURL: '{repo-placeholder}'
+ targetRevision: HEAD
+ directory:
+ exclude: application.yaml
+ project: default
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/application/bookinfo-versions.yaml b/Istio-Samples/ambient-argo/application/bookinfo-versions.yaml
new file mode 100644
index 00000000..c374bbee
--- /dev/null
+++ b/Istio-Samples/ambient-argo/application/bookinfo-versions.yaml
@@ -0,0 +1,72 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: reviews-v1
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: reviews
+ version: v1
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: reviews-v2
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: reviews
+ version: v2
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: reviews-v3
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: reviews
+ version: v3
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: productpage-v1
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: productpage
+ version: v1
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: ratings-v1
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: ratings
+ version: v1
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: details-v1
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: details
+ version: v1
+---
diff --git a/Istio-Samples/ambient-argo/application/details-waypoint.yaml b/Istio-Samples/ambient-argo/application/details-waypoint.yaml
new file mode 100644
index 00000000..d8a0ecb7
--- /dev/null
+++ b/Istio-Samples/ambient-argo/application/details-waypoint.yaml
@@ -0,0 +1,14 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: Gateway
+metadata:
+ annotations:
+ istio.io/for-service-account: bookinfo-details
+ labels:
+ istio.io/rev: stable
+ name: bookinfo-details
+spec:
+ gatewayClassName: istio-waypoint
+ listeners:
+ - name: mesh
+ port: 15008
+ protocol: HBONE
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/application/details.yaml b/Istio-Samples/ambient-argo/application/details.yaml
new file mode 100644
index 00000000..f0d72b59
--- /dev/null
+++ b/Istio-Samples/ambient-argo/application/details.yaml
@@ -0,0 +1,50 @@
+##################################################################################################
+# Details service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: details
+ labels:
+ app: details
+ service: details
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: details
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-details
+ labels:
+ account: details
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: details-v1
+ labels:
+ app: details
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: details
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: details
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-details
+ containers:
+ - name: details
+ image: docker.io/istio/examples-bookinfo-details-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/application/ingress-gateway.yaml b/Istio-Samples/ambient-argo/application/ingress-gateway.yaml
new file mode 100644
index 00000000..24c6fe36
--- /dev/null
+++ b/Istio-Samples/ambient-argo/application/ingress-gateway.yaml
@@ -0,0 +1,41 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: Gateway
+metadata:
+ name: bookinfo-gateway
+spec:
+ gatewayClassName: istio
+ listeners:
+ - name: http
+ port: 80
+ protocol: HTTP
+ allowedRoutes:
+ namespaces:
+ from: Same
+---
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: bookinfo
+spec:
+ parentRefs:
+ - name: bookinfo-gateway
+ rules:
+ - matches:
+ - path:
+ type: Exact
+ value: /productpage
+ - path:
+ type: PathPrefix
+ value: /static
+ - path:
+ type: Exact
+ value: /login
+ - path:
+ type: Exact
+ value: /logout
+ - path:
+ type: PathPrefix
+ value: /api/v1/products
+ backendRefs:
+ - name: productpage
+ port: 9080
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/application/namespace.yaml b/Istio-Samples/ambient-argo/application/namespace.yaml
new file mode 100644
index 00000000..1719eb58
--- /dev/null
+++ b/Istio-Samples/ambient-argo/application/namespace.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: ambient
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/application/productpage.yaml b/Istio-Samples/ambient-argo/application/productpage.yaml
new file mode 100644
index 00000000..c136feb6
--- /dev/null
+++ b/Istio-Samples/ambient-argo/application/productpage.yaml
@@ -0,0 +1,60 @@
+##################################################################################################
+# Productpage services
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: productpage
+ labels:
+ app: productpage
+ service: productpage
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: productpage
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-productpage
+ labels:
+ account: productpage
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: productpage-v1
+ labels:
+ app: productpage
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: productpage
+ version: v1
+ template:
+ metadata:
+ annotations:
+ prometheus.io/scrape: "true"
+ prometheus.io/port: "9080"
+ prometheus.io/path: "/metrics"
+ labels:
+ app: productpage
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-productpage
+ containers:
+ - name: productpage
+ image: docker.io/istio/examples-bookinfo-productpage-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ volumes:
+ - name: tmp
+ emptyDir: {}
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/application/ratings.yaml b/Istio-Samples/ambient-argo/application/ratings.yaml
new file mode 100644
index 00000000..69cfd8e2
--- /dev/null
+++ b/Istio-Samples/ambient-argo/application/ratings.yaml
@@ -0,0 +1,50 @@
+##################################################################################################
+# Ratings service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: ratings
+ labels:
+ app: ratings
+ service: ratings
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: ratings
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-ratings
+ labels:
+ account: ratings
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: ratings-v1
+ labels:
+ app: ratings
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ratings
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: ratings
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-ratings
+ containers:
+ - name: ratings
+ image: docker.io/istio/examples-bookinfo-ratings-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/application/reviews-waypoint.yaml b/Istio-Samples/ambient-argo/application/reviews-waypoint.yaml
new file mode 100644
index 00000000..e9eacf93
--- /dev/null
+++ b/Istio-Samples/ambient-argo/application/reviews-waypoint.yaml
@@ -0,0 +1,14 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: Gateway
+metadata:
+ annotations:
+ istio.io/for-service-account: bookinfo-reviews
+ labels:
+ istio.io/rev: rapid
+ name: bookinfo-reviews
+spec:
+ gatewayClassName: istio-waypoint
+ listeners:
+ - name: mesh
+ port: 15008
+ protocol: HBONE
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/application/reviews.yaml b/Istio-Samples/ambient-argo/application/reviews.yaml
new file mode 100644
index 00000000..6e389ad3
--- /dev/null
+++ b/Istio-Samples/ambient-argo/application/reviews.yaml
@@ -0,0 +1,143 @@
+##################################################################################################
+# Reviews service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: reviews
+ labels:
+ app: reviews
+ service: reviews
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: reviews
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-reviews
+ labels:
+ account: reviews
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v1
+ labels:
+ app: reviews
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-reviews
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v2
+ labels:
+ app: reviews
+ version: v2
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v2
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v2
+ spec:
+ serviceAccountName: bookinfo-reviews
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v2:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v3
+ labels:
+ app: reviews
+ version: v3
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v3
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v3
+ spec:
+ serviceAccountName: bookinfo-reviews
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v3:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/application/route-reviews-90-10.yaml b/Istio-Samples/ambient-argo/application/route-reviews-90-10.yaml
new file mode 100644
index 00000000..f7fddacc
--- /dev/null
+++ b/Istio-Samples/ambient-argo/application/route-reviews-90-10.yaml
@@ -0,0 +1,17 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: reviews
+spec:
+ parentRefs:
+ - group: ""
+ kind: Service
+ name: reviews
+ rules:
+ - backendRefs:
+ - name: reviews-v1
+ port: 9080
+ weight: 90
+ - name: reviews-v2
+ port: 9080
+ weight: 10
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/documentation/Ambient Upgrade - Strategies.png b/Istio-Samples/ambient-argo/documentation/Ambient Upgrade - Strategies.png
new file mode 100644
index 00000000..545a6a45
Binary files /dev/null and b/Istio-Samples/ambient-argo/documentation/Ambient Upgrade - Strategies.png differ
diff --git a/Istio-Samples/ambient-argo/documentation/argo-reference-arch.dot b/Istio-Samples/ambient-argo/documentation/argo-reference-arch.dot
new file mode 100644
index 00000000..eaae8e7a
--- /dev/null
+++ b/Istio-Samples/ambient-argo/documentation/argo-reference-arch.dot
@@ -0,0 +1,83 @@
+digraph G {
+ rankdir=LR
+ graph[fontname="Arial"]
+ node [fontname = "Arial"];
+ subgraph cluster_0 {
+ style=filled;
+ color=lightgrey;
+ node [style=filled,color=white,class=application];
+ meta[label="meta-application.yaml"]
+ app[label="application/application.yaml"]
+ meta -> app
+ istio[label="istio/*"]
+ meta -> istio
+ cni[label="istio/cni.yaml"]
+ istio -> cni
+ cpt[label="istio/control-plane-appset.yaml"]
+ istio -> cpt
+ ztunnel[label="istio/ztunnel.yaml"]
+ istio -> ztunnel
+ extras[label="istio/extras.yaml"]
+ istio -> extras
+ tags[label="istio/tags.yaml"]
+ istio -> tags
+ fontsize="32"
+ label = "ArgoCD Cluster";
+ }
+
+ subgraph cluster_1 {
+ node [style=filled,color=white]
+ subgraph cluster_istio {
+ fontsize="24"
+ label = "NS istio-system"
+ istiod18[label="Istio 1.18.5 Control"]
+ istiod19[label="Istio 1.19.3 Control"]
+ ztunnelds[label="ztunnel"]
+ cnids[label="cni"]
+ extrads[label="prometheus, etc"]
+ tagdef[label="tag default->1.18.5"]
+ tagrap[label="tag rapid->1.19.3"]
+ tagsta[label="tag stable->1.18.5"]
+ }
+
+ subgraph cluster_app {
+ rankdir=TB
+ node [style=filled];
+ appcontents[label="App Pods"]
+ appwp[label="App Waypoints"]
+ ig[label="Ingress Gateway"]
+ nwc[label="App Network Configs"]
+ fontsize="24"
+ label = "NS ambient";
+ }
+ fontsize="32"
+ label = "Application Cluster";
+ style=filled
+ color=deepskyblue
+
+ }
+
+ edge[weight=5]
+ appfiles[label="application/*"]
+ app -> appfiles [constraint=false]
+ appfiles -> appcontents
+ appfiles -> appwp
+ appfiles -> ig
+ appfiles -> nwc
+ ztunchart[label="ztunnel",class="helm"]
+ ztunnel -> ztunchart -> ztunnelds
+ istiodchart[label="istiod",class="helm"]
+ cpt -> istiodchart
+ istiodchart -> istiod18
+ istiodchart -> istiod19
+ cnichart[label="cni",class="helm"]
+ cni -> cnichart -> cnids
+ istiogh[label="istio github"]
+ extras -> istiogh -> extrads
+ tagchart[label="tag*"]
+ edge[weight=1]
+ tags->tagchart->tagdef
+ tagchart->tagrap
+ tagchart->tagsta
+
+}
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/documentation/argo-reference-arch.svg b/Istio-Samples/ambient-argo/documentation/argo-reference-arch.svg
new file mode 100644
index 00000000..1ab4199a
--- /dev/null
+++ b/Istio-Samples/ambient-argo/documentation/argo-reference-arch.svg
@@ -0,0 +1,333 @@
+
+
+G
+
+
+cluster_0
+
+ArgoCD Cluster
+
+
+cluster_1
+
+Application Cluster
+
+
+cluster_istio
+
+NS istio-system
+
+
+cluster_app
+
+NS ambient
+
+
+
+meta
+
+meta-application.yaml
+
+
+
+app
+
+application/application.yaml
+
+
+
+meta->app
+
+
+
+
+
+istio
+
+istio/*
+
+
+
+meta->istio
+
+
+
+
+
+appfiles
+
+application/*
+
+
+
+app->appfiles
+
+
+
+
+
+cni
+
+istio/cni.yaml
+
+
+
+istio->cni
+
+
+
+
+
+cpt
+
+istio/control-plane-appset.yaml
+
+
+
+istio->cpt
+
+
+
+
+
+ztunnel
+
+istio/ztunnel.yaml
+
+
+
+istio->ztunnel
+
+
+
+
+
+extras
+
+istio/extras.yaml
+
+
+
+istio->extras
+
+
+
+
+
+tags
+
+istio/tags.yaml
+
+
+
+istio->tags
+
+
+
+
+
+cnichart
+
+cni
+
+
+
+cni->cnichart
+
+
+
+
+
+istiodchart
+
+istiod
+
+
+
+cpt->istiodchart
+
+
+
+
+
+ztunchart
+
+ztunnel
+
+
+
+ztunnel->ztunchart
+
+
+
+
+
+istiogh
+
+istio github
+
+
+
+extras->istiogh
+
+
+
+
+
+tagchart
+
+tag*
+
+
+
+tags->tagchart
+
+
+
+
+
+istiod18
+
+Istio 1.18.5 Control
+
+
+
+istiod19
+
+Istio 1.19.3 Control
+
+
+
+ztunnelds
+
+ztunnel
+
+
+
+cnids
+
+cni
+
+
+
+extrads
+
+prometheus, etc
+
+
+
+tagdef
+
+tag default->1.18.5
+
+
+
+tagrap
+
+tag rapid->1.19.3
+
+
+
+tagsta
+
+tag stable->1.18.5
+
+
+
+appcontents
+
+App Pods
+
+
+
+appwp
+
+App Waypoints
+
+
+
+ig
+
+Ingress Gateway
+
+
+
+nwc
+
+App Network Configs
+
+
+
+appfiles->appcontents
+
+
+
+
+
+appfiles->appwp
+
+
+
+
+
+appfiles->ig
+
+
+
+
+
+appfiles->nwc
+
+
+
+
+
+ztunchart->ztunnelds
+
+
+
+
+
+istiodchart->istiod18
+
+
+
+
+
+istiodchart->istiod19
+
+
+
+
+
+cnichart->cnids
+
+
+
+
+
+istiogh->extrads
+
+
+
+
+
+tagchart->tagdef
+
+
+
+
+
+tagchart->tagrap
+
+
+
+
+
+tagchart->tagsta
+
+
+
+
+
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/istio/cni.yaml b/Istio-Samples/ambient-argo/istio/cni.yaml
new file mode 100644
index 00000000..85024c43
--- /dev/null
+++ b/Istio-Samples/ambient-argo/istio/cni.yaml
@@ -0,0 +1,33 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ name: istio-cni
+ namespace: argocd
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+spec:
+ project: default
+ destination:
+ name: ambient-cluster
+ namespace: kube-system
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
+ sources:
+ - repoURL: 'https://istio-release.storage.googleapis.com/charts'
+ targetRevision: 1.18.5
+ helm:
+ valuesObject:
+ revision: rapid
+ cni:
+ cniBinDir: "/home/kubernetes/bin"
+ valueFiles:
+ - >-
+ $values/manifests/charts/istio-cni/ambient-values.yaml
+ chart: cni
+ - repoURL: 'https://github.com/istio/istio.git'
+ targetRevision: HEAD
+ ref: values
diff --git a/Istio-Samples/ambient-argo/istio/control-plane-appset.yaml b/Istio-Samples/ambient-argo/istio/control-plane-appset.yaml
new file mode 100644
index 00000000..129091d0
--- /dev/null
+++ b/Istio-Samples/ambient-argo/istio/control-plane-appset.yaml
@@ -0,0 +1,39 @@
+apiVersion: argoproj.io/v1alpha1
+kind: ApplicationSet
+metadata:
+ name: istio-multi-control
+spec:
+ generators:
+ - list:
+ elements:
+ - version: 1.18.5
+ revision: 1-18-5
+ - version: 1.19.3
+ revision: 1-19-3
+ template:
+ metadata:
+ name: 'istio-control-{{revision}}'
+ spec:
+ project: default
+ sources:
+ - repoURL: 'https://istio-release.storage.googleapis.com/charts'
+ targetRevision: '{{version}}'
+ helm:
+ valuesObject:
+ revision: '{{revision}}'
+ valueFiles:
+ - >-
+ $values/manifests/charts/istio-control/istio-discovery/ambient-values.yaml
+ chart: istiod
+ - repoURL: 'https://github.com/istio/istio.git'
+ targetRevision: HEAD
+ ref: values
+ destination:
+ name: ambient-cluster
+ namespace: istio-system
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/istio/extras.yaml b/Istio-Samples/ambient-argo/istio/extras.yaml
new file mode 100644
index 00000000..47a7e2dc
--- /dev/null
+++ b/Istio-Samples/ambient-argo/istio/extras.yaml
@@ -0,0 +1,24 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ name: istio-addons
+ namespace: argocd
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+spec:
+ project: default
+ source:
+ repoURL: 'https://github.com/istio/istio.git'
+ targetRevision: HEAD
+ path: samples/addons
+ directory:
+ exclude: loki.yaml
+ destination:
+ name: ambient-cluster
+ namespace: istio-system
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/Istio-Samples/ambient-argo/istio/tags.yaml b/Istio-Samples/ambient-argo/istio/tags.yaml
new file mode 100644
index 00000000..264ca34d
--- /dev/null
+++ b/Istio-Samples/ambient-argo/istio/tags.yaml
@@ -0,0 +1,33 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ name: istio-tags
+ namespace: argocd
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+spec:
+ project: default
+ destination:
+ name: ambient-cluster
+ namespace: istio-system
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
+ source:
+ path: tag-chart
+ repoURL: '{repo-placeholder}'
+ targetRevision: HEAD
+ helm:
+ valuesObject:
+ base:
+ tags:
+ default:
+ revision: "1-18-5"
+ stable:
+ revision: "1-18-5"
+ rapid:
+ revision: "1-19-3"
+ istiodservice: "1-18-5" # This can be removed once ztunnel is on 1.20
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/istio/ztunnel.yaml b/Istio-Samples/ambient-argo/istio/ztunnel.yaml
new file mode 100644
index 00000000..e8cad644
--- /dev/null
+++ b/Istio-Samples/ambient-argo/istio/ztunnel.yaml
@@ -0,0 +1,25 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ name: istio-ztunnel
+ namespace: argocd
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+spec:
+ project: default
+ source:
+ repoURL: 'https://istio-release.storage.googleapis.com/charts'
+ targetRevision: 1.18.5
+ chart: ztunnel
+ helm:
+ valuesObject:
+ revision: rapid
+ destination:
+ name: ambient-cluster
+ namespace: istio-system
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=true
diff --git a/Istio-Samples/ambient-argo/meta-application.yaml b/Istio-Samples/ambient-argo/meta-application.yaml
new file mode 100644
index 00000000..19a9344c
--- /dev/null
+++ b/Istio-Samples/ambient-argo/meta-application.yaml
@@ -0,0 +1,31 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ name: meta-application
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+spec:
+ destination:
+ name: in-cluster
+ namespace: argocd
+ server: ''
+ sources:
+ - path: istio
+ repoURL: '{repo-placeholder}'
+ targetRevision: HEAD
+ - path: application
+ repoURL: '{repo-placeholder}'
+ targetRevision: HEAD
+ directory:
+ include: application.yaml
+ project: default
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ retry:
+ limit: 2
+ backoff:
+ duration: 5s
+ maxDuration: 3m0s
+ factor: 2
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/tag-chart/Chart.yaml b/Istio-Samples/ambient-argo/tag-chart/Chart.yaml
new file mode 100644
index 00000000..f7b73a56
--- /dev/null
+++ b/Istio-Samples/ambient-argo/tag-chart/Chart.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+name: tags
+version: 1.1.0
+tillerVersion: ">=2.7.2"
+description: Helm chart for deploying Istio cluster resources and CRDs
+keywords:
+ - istio
+sources:
+ - http://github.com/istio/istio
+engine: gotpl
+icon: https://istio.io/latest/favicons/android-192x192.png
diff --git a/Istio-Samples/ambient-argo/tag-chart/templates/mutatingwebhooks.yaml b/Istio-Samples/ambient-argo/tag-chart/templates/mutatingwebhooks.yaml
new file mode 100644
index 00000000..e8ef3e57
--- /dev/null
+++ b/Istio-Samples/ambient-argo/tag-chart/templates/mutatingwebhooks.yaml
@@ -0,0 +1,109 @@
+{{- define "core" }}
+- name: {{.Prefix}}sidecar-injector.istio.io
+ clientConfig:
+ {{- if .injectionURL }}
+ url: "{{ .injectionURL }}"
+ {{- else }}
+ service:
+ name: istiod{{- if not (eq .revision "") }}-{{ .revision }}{{- end }}
+ namespace: {{ .Release.Namespace }}
+ path: "{{ .injectionPath }}"
+ {{- end }}
+ sideEffects: None
+ rules:
+ - operations: [ "CREATE" ]
+ apiGroups: [""]
+ apiVersions: ["v1"]
+ resources: ["pods"]
+ failurePolicy: Fail
+ admissionReviewVersions: ["v1beta1", "v1"]
+{{- end }}
+
+{{- range $tagName, $tag := $.Values.base.tags }}
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+{{- if eq $.Release.Namespace "istio-system"}}
+ name: istio-revision-tag-{{ $tagName }}
+{{- else }}
+ name: istio-revision-tag-{{ $tagName }}-{{ $.Release.Namespace }}
+{{- end }}
+ labels:
+ istio.io/tag: {{ $tagName }}
+ istio.io/rev: {{ $tag.revision | default "default" }}
+ install.operator.istio.io/owning-resource: {{ $.Values.ownerName | default "unknown" }}
+ operator.istio.io/component: "Pilot"
+ app: sidecar-injector
+ release: {{ $.Release.Name }}
+webhooks:
+{{- include "core" (mergeOverwrite (deepCopy $) (deepCopy $tag) (dict "Prefix" "rev.namespace.") ) }}
+ namespaceSelector:
+ matchExpressions:
+ - key: istio.io/rev
+ operator: In
+ values:
+ - "{{ $tagName }}"
+ - key: istio-injection
+ operator: DoesNotExist
+ objectSelector:
+ matchExpressions:
+ - key: sidecar.istio.io/inject
+ operator: NotIn
+ values:
+ - "false"
+{{- include "core" (mergeOverwrite (deepCopy $) (deepCopy $tag) (dict "Prefix" "rev.object.") ) }}
+ namespaceSelector:
+ matchExpressions:
+ - key: istio.io/rev
+ operator: DoesNotExist
+ - key: istio-injection
+ operator: DoesNotExist
+ objectSelector:
+ matchExpressions:
+ - key: sidecar.istio.io/inject
+ operator: NotIn
+ values:
+ - "false"
+ - key: istio.io/rev
+ operator: In
+ values:
+ - "{{ $tagName }}"
+
+{{- /* When the tag is "default" we want to create webhooks for the default revision */}}
+{{- /* These webhooks should be kept in sync with istio-discovery/templates/mutatingwebhook.yaml */}}
+{{- if (eq $tagName "default") }}
+
+{{- /* Case 1: Namespace selector enabled, and object selector is not injected */}}
+{{- include "core" (mergeOverwrite (deepCopy $) (deepCopy $tag) (dict "Prefix" "namespace.") ) }}
+ namespaceSelector:
+ matchExpressions:
+ - key: istio-injection
+ operator: In
+ values:
+ - enabled
+ objectSelector:
+ matchExpressions:
+ - key: sidecar.istio.io/inject
+ operator: NotIn
+ values:
+ - "false"
+
+{{- /* Case 2: no namespace label, but object selector is enabled (and revision label is not, which has priority) */}}
+{{- include "core" (mergeOverwrite (deepCopy $) (deepCopy $tag) (dict "Prefix" "object.") ) }}
+ namespaceSelector:
+ matchExpressions:
+ - key: istio-injection
+ operator: DoesNotExist
+ - key: istio.io/rev
+ operator: DoesNotExist
+ objectSelector:
+ matchExpressions:
+ - key: sidecar.istio.io/inject
+ operator: In
+ values:
+ - "true"
+ - key: istio.io/rev
+ operator: DoesNotExist
+{{- end }}
+---
+{{- end }}
diff --git a/Istio-Samples/ambient-argo/tag-chart/templates/shimservice.yaml b/Istio-Samples/ambient-argo/tag-chart/templates/shimservice.yaml
new file mode 100644
index 00000000..ae63ae73
--- /dev/null
+++ b/Istio-Samples/ambient-argo/tag-chart/templates/shimservice.yaml
@@ -0,0 +1,31 @@
+{{- if ((.Values.base.tags.default).revision) }}
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ install.operator.istio.io/owning-resource: {{ .Values.ownerName | default "unknown" }}
+ operator.istio.io/component: "Pilot"
+ app: istiod
+ istio: pilot
+ release: {{ .Release.Name }}
+ name: istiod
+ namespace: istio-system
+spec:
+ ports:
+ - name: grpc-xds
+ port: 15010
+ protocol: TCP
+ - name: https-dns
+ port: 15012
+ protocol: TCP
+ - name: https-webhook
+ port: 443
+ protocol: TCP
+ targetPort: 15017
+ - name: http-monitoring
+ port: 15014
+ protocol: TCP
+ selector:
+ app: istiod
+ istio.io/rev: {{ .Values.base.istiodservice }}
+{{- end }}
\ No newline at end of file
diff --git a/Istio-Samples/ambient-argo/tag-chart/templates/validatingwebhook.yaml b/Istio-Samples/ambient-argo/tag-chart/templates/validatingwebhook.yaml
new file mode 100644
index 00000000..793453a7
--- /dev/null
+++ b/Istio-Samples/ambient-argo/tag-chart/templates/validatingwebhook.yaml
@@ -0,0 +1,48 @@
+{{- if .Values.global.configValidation }}
+{{- if hasKey .Values.base.tags "default" }}
+{{- $tag := .Values.base.tags.default }}
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+ name: istiod-default-validator
+ labels:
+ app: istiod
+ istio: istiod
+ istio.io/rev: {{ $tag.revision | default "default" }}
+ istio.io/tag: "default"
+ # Required to make sure this resource is removed
+ # when purging Istio resources
+ operator.istio.io/component: Pilot
+webhooks:
+ - name: validation.istio.io
+ clientConfig:
+ {{- if $tag.validationURL }}
+ url: {{ $tag.validationURL }}
+ {{- else }}
+ service:
+ name: istiod{{- if not (eq $tag.revision "") }}-{{ $tag.revision }}{{- end }}
+ namespace: {{ .Values.global.istioNamespace }}
+ path: "/validate"
+ {{- end }}
+ rules:
+ - operations:
+ - CREATE
+ - UPDATE
+ apiGroups:
+ - security.istio.io
+ - networking.istio.io
+ - telemetry.istio.io
+ apiVersions:
+ - "*"
+ resources:
+ - "*"
+ failurePolicy: Ignore
+ sideEffects: None
+ admissionReviewVersions: ["v1beta1", "v1"]
+ objectSelector:
+ matchExpressions:
+ - key: istio.io/rev
+ operator: DoesNotExist
+---
+{{- end }}
+{{- end }}
diff --git a/Istio-Samples/ambient-argo/tag-chart/values.yaml b/Istio-Samples/ambient-argo/tag-chart/values.yaml
new file mode 100644
index 00000000..f27642b7
--- /dev/null
+++ b/Istio-Samples/ambient-argo/tag-chart/values.yaml
@@ -0,0 +1,41 @@
+global:
+
+ # ImagePullSecrets for control plane ServiceAccount, list of secrets in the same namespace
+ # to use for pulling any images in pods that reference this ServiceAccount.
+ # Must be set for any cluster configured with private docker registry.
+ imagePullSecrets: []
+
+ # Used to locate istiod.
+ istioNamespace: istio-system
+
+ istiod:
+ enableAnalysis: false
+
+ configValidation: true
+ externalIstiod: false
+ remotePilotAddress: ""
+
+base:
+ # Used for helm2 to add the CRDs to templates.
+ enableCRDTemplates: false
+
+ # Validation webhook configuration url
+ # For example: https://$remotePilotAddress:15017/validate
+ validationURL: ""
+
+ # For istioctl usage to disable istio config crds in base
+ enableIstioConfigCRDs: true
+
+ # Defines the mapping from revision tags to revisions.
+ #
+ # The following fields can be set for each revision tag:
+ # (1) revision (REQUIRED): the revision to use for this revision tag.
+ # (2) namespace: the namespace containing the istiod revision.
+ # (3) validationURL: the URL to use for validation on this revision tag.
+ # (4) injectionURL: the URL to for injection on this revision tag.
+ # (5) injectionPath: the injection path to use for this tag webhook.
+ #
+ # Note that the revision tag "default" has additional semantic meaning as it
+ # controls the revision that performs validation and the revision that handles
+ # injection for default selectors ("istio-injection=enabled" and "sidecar.istio.io/inject").
+ tags: {}
diff --git a/Istio-Samples/bookinfo/README.md b/Istio-Samples/bookinfo/README.md
new file mode 100644
index 00000000..ff84972e
--- /dev/null
+++ b/Istio-Samples/bookinfo/README.md
@@ -0,0 +1,234 @@
+# Bookinfo Sample
+
+See .
+
+**Note**: We need the owner of the PR to perform the appropriate testing with built/pushed images to their own docker repository before we would build/push images to the official Istio repository.
+
+## General Setup
+
+```bash
+# This defines the docker hub to use when running integration tests and building docker images
+# eg: HUB="docker.io/istio", HUB="gcr.io/istio-testing"
+export HUB="docker.io/$USER"
+
+# This defines the docker tag to use when running integration tests and
+# building docker images to be your user id. You may also set this variable
+# this to any other legitimate docker tag.
+export TAG=
+```
+
+## Compile code
+
+```bash
+cd samples/bookinfo
+BOOKINFO_TAG=$TAG BOOKINFO_HUB=$HUB src/build-services.sh
+```
+
+For example:
+
+```bash
+$ BOOKINFO_TAG=test1.0 BOOKINFO_HUB=docker.io/user1 src/build-services.sh
++++ dirname ./build-services.sh
+++ cd .
+++ pwd
++ SCRIPTDIR=/work/samples/bookinfo/src
++ cd /work/samples/bookinfo/src/../../..
++ h=docker.io/user1
++ t=test1.0
++ [[ docker.io/user1 == \i\s\t\i\o ]]
++ [[ docker.io/user1 == \d\o\c\k\e\r\.\i\o\/\i\s\t\i\o ]]
++ plat=linux/amd64
++ [[ '' == \t\r\u\e ]]
++ env TAG=test1.0 HUB=docker.io/user1 docker buildx bake -f samples/bookinfo/src/docker-bake.hcl --set '*.platform=linux/amd64'
+[+] Building 1.9s (123/133)
+ => [examples-bookinfo-ratings-v-faulty internal] load build definition from Dockerfile 0.0s
+ => => transferring dockerfile: 1.05kB 0.0s
+...
+ => CACHED [examples-bookinfo-ratings-v-faulty 4/6] COPY ratings.js /opt/microservices/ 0.0s
+ => CACHED [examples-bookinfo-ratings-v-faulty 5/6] WORKDIR /opt/microservices 0.0s
+ => CACHED [examples-bookinfo-ratings-v-faulty 6/6] RUN npm install 0.0s
+WARNING: No output specified for examples-bookinfo-mysqldb, examples-bookinfo-ratings-v-faulty, examples-bookinfo-reviews-v2, examples-bookinfo-reviews-v3, examples-bookinfo-productpage-v-flooding, examples-bookinfo-ratings-v-unhealthy, examples-bookinfo-ratings-v-unavailable, examples-bookinfo-ratings-v1, examples-bookinfo-details-v2, examples-bookinfo-reviews-v1, examples-bookinfo-productpage-v1, examples-bookinfo-ratings-v-delayed, examples-bookinfo-details-v1, examples-bookinfo-ratings-v2, examples-bookinfo-mongodb target(s) with docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load
+```
+
+The code for the bookinfo sample is now compiled and built. The bookinfo versions are different from Istio versions since the sample should work with any version of Istio.
+
+## Build docker images
+
+```bash
+cd samples/bookinfo
+BOOKINFO_TAG=$TAG BOOKINFO_HUB=$HUB src/build-services.sh --load
+```
+
+For example:
+
+```bash
+$ BOOKINFO_TAG=test1.0 BOOKINFO_HUB=docker.io/user1 src/build-services.sh --load
++++ dirname ./build-services.sh
+++ cd .
+++ pwd
++ SCRIPTDIR=/work/samples/bookinfo/src
++ cd /work/samples/bookinfo/src/../../..
++ h=docker.io/user1
++ t=test1.0
++ [[ docker.io/user1 == \i\s\t\i\o ]]
++ [[ docker.io/user1 == \d\o\c\k\e\r\.\i\o\/\i\s\t\i\o ]]
++ plat=linux/amd64
++ [[ '' == \t\r\u\e ]]
+...
+ => [examples-bookinfo-productpage-v-flooding] exporting to docker image format 10.4s
+ => => exporting layers 0.0s
+ => => exporting manifest sha256:5046deeca78c67f0977fa627b3c2a98ba380b09f4dabf5620040fbf723785f6a 0.0s
+ => => exporting config sha256:5a632c874e649f6492d5a6592a3da2b9ee3fca8d6f55bfbc0249b865eb8579be 0.0s
+ => => sending tarball 10.4s
+ => importing to docker 0.1s
+ => importing to docker 0.0s
+ => importing to docker 0.0s
+ => importing to docker 0.0s
+ => importing to docker 0.0s
+ => importing to docker 0.0s
+ => importing to docker 0.0s
+ => importing to docker 0.0s
+ => importing to docker 0.0s
+ => importing to docker 0.0s
+ => importing to docker 0.0s
+ => importing to docker 0.1s
+ => importing to docker 0.3s
+ => importing to docker 0.2s
+ => importing to docker 0.1s
++ [[ true == \t\r\u\e ]]
++ find ./samples/bookinfo/platform -name '*bookinfo*.yaml' -exec sed -i.bak 's#image:.*\(\/examples-bookinfo-.*\):.*#image: docker.io\/user1\1:test1.0#g' '{}' +/ay
+```
+
+Docker images are now created.
+
+## Push docker images to docker hub
+
+After the local build is successful, you will need to push the images to Docker hub. You may need to login to Docker before you run the command using `docker login`.
+
+```bash
+cd samples/bookinfo
+BOOKINFO_TAG=$TAG BOOKINFO_HUB=$HUB src/build-services.sh --push
+```
+
+For example:
+
+```bash
+$ BOOKINFO_TAG=test1.0 BOOKINFO_HUB=docker.io/user1 src/build-services.sh --push
++++ dirname ./build-services.sh
+++ cd .
+++ pwd
++ SCRIPTDIR=/work/samples/bookinfo/src
++ cd /work/samples/bookinfo/src/../../..
++ h=docker.io/user1
++ t=test1.0
++ [[ docker.io/user1 == \i\s\t\i\o ]]
++ [[ docker.io/user1 == \d\o\c\k\e\r\.\i\o\/\i\s\t\i\o ]]
++ plat=linux/amd64
++ [[ '' == \t\r\u\e ]]
++ env TAG=test1.0 HUB=docker.io/user1 docker buildx bake -f samples/bookinfo/src/docker-bake.hcl --set '*.platform=linux/amd64' --push
+...
+ => => pushing layers 11.1s
+ => => pushing manifest for docker.io/user1/examples-bookinfo-reviews-v3:test1.0@sha256:4c9e2dfcabdfc55fba9037967ee412690b23d676481713eb88985926e229c8db 0.7s
+ => [auth] user1/examples-bookinfo-ratings-v2:pull,push token for registry-1.docker.io 0.0s
+ => [auth] user1/examples-bookinfo-ratings-v-delayed:pull,push token for registry-1.docker.io 0.0s
+ => [auth] user1/examples-bookinfo-ratings-v-unavailable:pull,push token for registry-1.docker.io 0.0s
+ => [auth] user1/examples-bookinfo-ratings-v-unhealthy:pull,push token for registry-1.docker.io 0.0s
+ => [auth] user1/examples-bookinfo-ratings-v-faulty:pull,push token for registry-1.docker.io 0.0s
+ => [auth] user1/examples-bookinfo-mongodb:pull,push token for registry-1.docker.io 0.0s
+ => [auth] user1/examples-bookinfo-details-v1:pull,push token for registry-1.docker.io 0.0s
+ => [auth] user1/examples-bookinfo-productpage-v1:pull,push token for registry-1.docker.io 0.0s
+ => [auth] user1/examples-bookinfo-details-v2:pull,push token for registry-1.docker.io 0.0s
+ => [auth] user1/examples-bookinfo-productpage-v-flooding:pull,push token for registry-1.docker.io 0.0s
+ => [auth] user1/examples-bookinfo-reviews-v1:pull,push token for registry-1.docker.io 0.0s
+ => [auth] user1/examples-bookinfo-reviews-v3:pull,push token for registry-1.docker.io 0.0s
+ => [auth] user1/examples-bookinfo-reviews-v2:pull,push token for registry-1.docker.io 0.0s
++ [[ true == \t\r\u\e ]]
++ find ./samples/bookinfo/platform -name '*bookinfo*.yaml' -exec sed -i.bak 's#image:.*\(\/examples-bookinfo-.*\):.*#image: docker.io\/user1\1:test1.0#g' '{}' +
+```
+
+## Update YAML files to point to the newly created images
+
+You need to update the YAML file with the latest tag that you used during the build, eg: `$HUB:$TAG`.
+
+Run the following script to update the YAML files in one step.
+
+```bash
+cd samples/bookinfo
+export BOOKINFO_UPDATE=true
+BOOKINFO_TAG=test1.0 BOOKINFO_HUB=user1 src/build-services.sh
+```
+
+For example:
+
+```bash
+$ export BOOKINFO_UPDATE=true
+$ BOOKINFO_TAG=test1.0 BOOKINFO_HUB=user1 src/build-services.sh
++++ dirname samples/bookinfo/src/build-services.sh
+++ cd samples/bookinfo/src
+++ pwd
++ SCRIPTDIR=/work/samples/bookinfo/src
++ cd /work/samples/bookinfo/src/../../..
++ h=user1
++ t=test1.0
++ [[ user1 == \i\s\t\i\o ]]
++ [[ user1 == \d\o\c\k\e\r\.\i\o\/\i\s\t\i\o ]]
++ plat=linux/amd64
++ [[ '' == \t\r\u\e ]]
++ env TAG=test1.0 HUB=docker.io/user1 docker buildx bake -f samples/bookinfo/src/docker-bake.hcl --set '*.platform=linux/amd64'
+...
+ => CACHED [examples-bookinfo-ratings-v-faulty 4/6] COPY ratings.js /opt/microservices/ 0.0s
+ => CACHED [examples-bookinfo-ratings-v-faulty 5/6] WORKDIR /opt/microservices 0.0s
+ => CACHED [examples-bookinfo-ratings-v-faulty 6/6] RUN npm install 0.0s
+WARNING: No output specified for examples-bookinfo-mysqldb, examples-bookinfo-ratings-v-faulty, examples-bookinfo-reviews-v2, examples-bookinfo-reviews-v3, examples-bookinfo-productpage-v-flooding, examples-bookinfo-ratings-v-unhealthy, examples-bookinfo-ratings-v-unavailable, examples-bookinfo-ratings-v1, examples-bookinfo-details-v2, examples-bookinfo-reviews-v1, examples-bookinfo-productpage-v1, examples-bookinfo-ratings-v-delayed, examples-bookinfo-details-v1, examples-bookinfo-ratings-v2, examples-bookinfo-mongodb target(s) with docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load
++ [[ true == \t\r\u\e ]]
++ find ./samples/bookinfo/platform -name '*bookinfo*.yaml' -exec sed -i.bak 's#image:.*\(\/examples-bookinfo-.*\):.*#image: user1\1:test1.0#g' '{}' +
+```
+
+Verify that expected image eg: `user1/examples-bookinfo-*:test1.0` is updated in `platform/kube/bookinfo*.yaml` files.
+
+## Tests
+
+Test that the bookinfo samples work with the latest image eg: `user1/examples-bookinfo-*:test1.0` that you pushed.
+
+```bash
+$ cd ../../
+$ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
+serviceaccount/bookinfo-details created
+deployment.apps/details-v1 created
+serviceaccount/bookinfo-ratings created
+...
+```
+
+Wait for all the pods to be in `Running` start.
+
+```bash
+$ kubectl get pods
+NAME READY STATUS RESTARTS AGE
+details-v1-7f556f5c6b-485l2 2/2 Running 0 10m
+productpage-v1-84c8f95c8d-tlml2 2/2 Running 0 10m
+ratings-v1-66777f856b-2ls78 2/2 Running 0 10m
+reviews-v1-64c47f4f44-rx642 2/2 Running 0 10m
+reviews-v2-66b6b95f44-s5nt6 2/2 Running 0 10m
+reviews-v3-7f69dd7fd4-zjvc8 2/2 Running 0 10m
+```
+
+Once all the pods are in the `Running` state. Test if the bookinfo works through cli.
+
+```bash
+$ kubectl exec -it "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl productpage:9080/productpage | grep -o ".* "
+Simple Bookstore App
+```
+
+You can also test it by hitting productpage in the browser.
+
+```bash
+http://192.168.39.116:31395/productpage
+```
+
+You should see the following in the browser.
+
+![star](https://user-images.githubusercontent.com/2920003/86032538-212ff900-ba55-11ea-9492-d4bc90656a02.png)
+
+**Note**: If everything works as mentioned above, request a new official set of images be built and pushed from the reviewer, and add another commit to the original PR with the version changes.
+
+Bookinfo is tested by istio.io integration tests. You can find them under [tests](https://github.com/istio/istio.io/tree/master/tests) in the [istio/istio.io](https://github.com/istio/istio.io) repository.
diff --git a/Istio-Samples/bookinfo/demo-profile-no-gateways.yaml b/Istio-Samples/bookinfo/demo-profile-no-gateways.yaml
new file mode 100644
index 00000000..4edaba40
--- /dev/null
+++ b/Istio-Samples/bookinfo/demo-profile-no-gateways.yaml
@@ -0,0 +1,12 @@
+# IOP configuration used to install the demo profile without gateways.
+apiVersion: install.istio.io/v1alpha1
+kind: IstioOperator
+spec:
+ profile: demo
+ components:
+ ingressGateways:
+ - name: istio-ingressgateway
+ enabled: false
+ egressGateways:
+ - name: istio-egressgateway
+ enabled: false
diff --git a/Istio-Samples/bookinfo/gateway-api/bookinfo-gateway.yaml b/Istio-Samples/bookinfo/gateway-api/bookinfo-gateway.yaml
new file mode 100644
index 00000000..3870a4cc
--- /dev/null
+++ b/Istio-Samples/bookinfo/gateway-api/bookinfo-gateway.yaml
@@ -0,0 +1,41 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: Gateway
+metadata:
+ name: bookinfo-gateway
+spec:
+ gatewayClassName: istio
+ listeners:
+ - name: http
+ port: 80
+ protocol: HTTP
+ allowedRoutes:
+ namespaces:
+ from: Same
+---
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: bookinfo
+spec:
+ parentRefs:
+ - name: bookinfo-gateway
+ rules:
+ - matches:
+ - path:
+ type: Exact
+ value: /productpage
+ - path:
+ type: PathPrefix
+ value: /static
+ - path:
+ type: Exact
+ value: /login
+ - path:
+ type: Exact
+ value: /logout
+ - path:
+ type: PathPrefix
+ value: /api/v1/products
+ backendRefs:
+ - name: productpage
+ port: 9080
diff --git a/Istio-Samples/bookinfo/gateway-api/route-all-v1.yaml b/Istio-Samples/bookinfo/gateway-api/route-all-v1.yaml
new file mode 100644
index 00000000..d92cbf5d
--- /dev/null
+++ b/Istio-Samples/bookinfo/gateway-api/route-all-v1.yaml
@@ -0,0 +1,60 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: reviews
+spec:
+ parentRefs:
+ - group: ""
+ kind: Service
+ name: reviews
+ port: 9080
+ rules:
+ - backendRefs:
+ - name: reviews-v1
+ port: 9080
+---
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: productpage
+spec:
+ parentRefs:
+ - group: ""
+ kind: Service
+ name: productpage
+ port: 9080
+ rules:
+ - backendRefs:
+ - name: productpage-v1
+ port: 9080
+---
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: ratings
+spec:
+ parentRefs:
+ - group: ""
+ kind: Service
+ name: ratings
+ port: 9080
+ rules:
+ - backendRefs:
+ - name: ratings-v1
+ port: 9080
+---
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: details
+spec:
+ parentRefs:
+ - group: ""
+ kind: Service
+ name: details
+ port: 9080
+ rules:
+ - backendRefs:
+ - name: details-v1
+ port: 9080
+---
diff --git a/Istio-Samples/bookinfo/gateway-api/route-reviews-50-v3.yaml b/Istio-Samples/bookinfo/gateway-api/route-reviews-50-v3.yaml
new file mode 100644
index 00000000..3da60590
--- /dev/null
+++ b/Istio-Samples/bookinfo/gateway-api/route-reviews-50-v3.yaml
@@ -0,0 +1,18 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: reviews
+spec:
+ parentRefs:
+ - group: ""
+ kind: Service
+ name: reviews
+ port: 9080
+ rules:
+ - backendRefs:
+ - name: reviews-v1
+ port: 9080
+ weight: 50
+ - name: reviews-v3
+ port: 9080
+ weight: 50
diff --git a/Istio-Samples/bookinfo/gateway-api/route-reviews-90-10.yaml b/Istio-Samples/bookinfo/gateway-api/route-reviews-90-10.yaml
new file mode 100644
index 00000000..53cdd08b
--- /dev/null
+++ b/Istio-Samples/bookinfo/gateway-api/route-reviews-90-10.yaml
@@ -0,0 +1,18 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: reviews
+spec:
+ parentRefs:
+ - group: ""
+ kind: Service
+ name: reviews
+ port: 9080
+ rules:
+ - backendRefs:
+ - name: reviews-v1
+ port: 9080
+ weight: 90
+ - name: reviews-v2
+ port: 9080
+ weight: 10
diff --git a/Istio-Samples/bookinfo/gateway-api/route-reviews-v1.yaml b/Istio-Samples/bookinfo/gateway-api/route-reviews-v1.yaml
new file mode 100644
index 00000000..cd222b2a
--- /dev/null
+++ b/Istio-Samples/bookinfo/gateway-api/route-reviews-v1.yaml
@@ -0,0 +1,14 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: reviews
+spec:
+ parentRefs:
+ - group: ""
+ kind: Service
+ name: reviews
+ port: 9080
+ rules:
+ - backendRefs:
+ - name: reviews-v1
+ port: 9080
diff --git a/Istio-Samples/bookinfo/gateway-api/route-reviews-v3.yaml b/Istio-Samples/bookinfo/gateway-api/route-reviews-v3.yaml
new file mode 100644
index 00000000..94905fa1
--- /dev/null
+++ b/Istio-Samples/bookinfo/gateway-api/route-reviews-v3.yaml
@@ -0,0 +1,14 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: reviews
+spec:
+ parentRefs:
+ - group: ""
+ kind: Service
+ name: reviews
+ port: 9080
+ rules:
+ - backendRefs:
+ - name: reviews-v3
+ port: 9080
diff --git a/Istio-Samples/bookinfo/networking/bookinfo-gateway.yaml b/Istio-Samples/bookinfo/networking/bookinfo-gateway.yaml
new file mode 100644
index 00000000..8e2996c0
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/bookinfo-gateway.yaml
@@ -0,0 +1,43 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: Gateway
+metadata:
+ name: bookinfo-gateway
+spec:
+ # The selector matches the ingress gateway pod labels.
+ # If you installed Istio using Helm following the standard documentation, this would be "istio=ingress"
+ selector:
+ istio: ingressgateway # use istio default controller
+ servers:
+ - port:
+ number: 8080
+ name: http
+ protocol: HTTP
+ hosts:
+ - "*"
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: bookinfo
+spec:
+ hosts:
+ - "*"
+ gateways:
+ - bookinfo-gateway
+ http:
+ - match:
+ - uri:
+ exact: /productpage
+ - uri:
+ prefix: /static
+ - uri:
+ exact: /login
+ - uri:
+ exact: /logout
+ - uri:
+ prefix: /api/v1/products
+ route:
+ - destination:
+ host: productpage
+ port:
+ number: 9080
diff --git a/Istio-Samples/bookinfo/networking/certmanager-gateway.yaml b/Istio-Samples/bookinfo/networking/certmanager-gateway.yaml
new file mode 100644
index 00000000..3fa65378
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/certmanager-gateway.yaml
@@ -0,0 +1,35 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: Gateway
+metadata:
+ name: cert-manager-gateway
+ namespace: istio-system
+spec:
+ selector:
+ istio: ingressgateway
+ servers:
+ - port:
+ number: 80
+ name: http
+ protocol: HTTP
+ hosts:
+ - "*"
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: cert-manager
+ namespace: istio-system
+spec:
+ hosts:
+ - "*"
+ gateways:
+ - cert-manager-gateway
+ http:
+ - match:
+ - uri:
+ prefix: /.well-known/acme-challenge/
+ route:
+ - destination:
+ host: cert-manager-resolver
+ port:
+ number: 8089
diff --git a/Istio-Samples/bookinfo/networking/destination-rule-all-mtls.yaml b/Istio-Samples/bookinfo/networking/destination-rule-all-mtls.yaml
new file mode 100644
index 00000000..2a19c3fb
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/destination-rule-all-mtls.yaml
@@ -0,0 +1,74 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+ name: productpage
+spec:
+ host: productpage
+ trafficPolicy:
+ tls:
+ mode: ISTIO_MUTUAL
+ subsets:
+ - name: v1
+ labels:
+ version: v1
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+ name: reviews
+spec:
+ host: reviews
+ trafficPolicy:
+ tls:
+ mode: ISTIO_MUTUAL
+ subsets:
+ - name: v1
+ labels:
+ version: v1
+ - name: v2
+ labels:
+ version: v2
+ - name: v3
+ labels:
+ version: v3
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+ name: ratings
+spec:
+ host: ratings
+ trafficPolicy:
+ tls:
+ mode: ISTIO_MUTUAL
+ subsets:
+ - name: v1
+ labels:
+ version: v1
+ - name: v2
+ labels:
+ version: v2
+ - name: v2-mysql
+ labels:
+ version: v2-mysql
+ - name: v2-mysql-vm
+ labels:
+ version: v2-mysql-vm
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+ name: details
+spec:
+ host: details
+ trafficPolicy:
+ tls:
+ mode: ISTIO_MUTUAL
+ subsets:
+ - name: v1
+ labels:
+ version: v1
+ - name: v2
+ labels:
+ version: v2
+---
diff --git a/Istio-Samples/bookinfo/networking/destination-rule-all.yaml b/Istio-Samples/bookinfo/networking/destination-rule-all.yaml
new file mode 100644
index 00000000..96be6993
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/destination-rule-all.yaml
@@ -0,0 +1,62 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+ name: productpage
+spec:
+ host: productpage
+ subsets:
+ - name: v1
+ labels:
+ version: v1
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+ name: reviews
+spec:
+ host: reviews
+ subsets:
+ - name: v1
+ labels:
+ version: v1
+ - name: v2
+ labels:
+ version: v2
+ - name: v3
+ labels:
+ version: v3
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+ name: ratings
+spec:
+ host: ratings
+ subsets:
+ - name: v1
+ labels:
+ version: v1
+ - name: v2
+ labels:
+ version: v2
+ - name: v2-mysql
+ labels:
+ version: v2-mysql
+ - name: v2-mysql-vm
+ labels:
+ version: v2-mysql-vm
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+ name: details
+spec:
+ host: details
+ subsets:
+ - name: v1
+ labels:
+ version: v1
+ - name: v2
+ labels:
+ version: v2
+---
diff --git a/Istio-Samples/bookinfo/networking/destination-rule-reviews.yaml b/Istio-Samples/bookinfo/networking/destination-rule-reviews.yaml
new file mode 100644
index 00000000..69f30f1d
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/destination-rule-reviews.yaml
@@ -0,0 +1,19 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+ name: reviews
+spec:
+ host: reviews
+ trafficPolicy:
+ loadBalancer:
+ simple: RANDOM
+ subsets:
+ - name: v1
+ labels:
+ version: v1
+ - name: v2
+ labels:
+ version: v2
+ - name: v3
+ labels:
+ version: v3
diff --git a/Istio-Samples/bookinfo/networking/egress-rule-google-apis.yaml b/Istio-Samples/bookinfo/networking/egress-rule-google-apis.yaml
new file mode 100644
index 00000000..d35e3ac1
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/egress-rule-google-apis.yaml
@@ -0,0 +1,46 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: googleapis
+spec:
+ hosts:
+ - www.googleapis.com
+ ports:
+ - number: 80
+ name: http
+ protocol: HTTP
+ - number: 443
+ name: https
+ protocol: HTTPS
+ resolution: DNS
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: rewrite-port-for-googleapis
+spec:
+ hosts:
+ - www.googleapis.com
+ http:
+ - match:
+ - port: 80
+ route:
+ - destination:
+ host: www.googleapis.com
+ port:
+ number: 443
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+ name: originate-tls-for-googleapis
+spec:
+ host: www.googleapis.com
+ trafficPolicy:
+ loadBalancer:
+ simple: ROUND_ROBIN
+ portLevelSettings:
+ - port:
+ number: 443
+ tls:
+ mode: SIMPLE # initiates HTTPS when accessing www.googleapis.com
diff --git a/Istio-Samples/bookinfo/networking/fault-injection-details-v1.yaml b/Istio-Samples/bookinfo/networking/fault-injection-details-v1.yaml
new file mode 100644
index 00000000..c4550925
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/fault-injection-details-v1.yaml
@@ -0,0 +1,32 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: details
+spec:
+ hosts:
+ - details
+ http:
+ - fault:
+ abort:
+ httpStatus: 555
+ percentage:
+ value: 100
+ route:
+ - destination:
+ host: details
+ subset: v1
+ - route:
+ - destination:
+ host: details
+ subset: v1
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+ name: details
+spec:
+ host: details
+ subsets:
+ - name: v1
+ labels:
+ version: v1
\ No newline at end of file
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-all-v1.yaml b/Istio-Samples/bookinfo/networking/virtual-service-all-v1.yaml
new file mode 100644
index 00000000..6811e31d
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-all-v1.yaml
@@ -0,0 +1,52 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: productpage
+spec:
+ hosts:
+ - productpage
+ http:
+ - route:
+ - destination:
+ host: productpage
+ subset: v1
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: reviews
+spec:
+ hosts:
+ - reviews
+ http:
+ - route:
+ - destination:
+ host: reviews
+ subset: v1
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: ratings
+spec:
+ hosts:
+ - ratings
+ http:
+ - route:
+ - destination:
+ host: ratings
+ subset: v1
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: details
+spec:
+ hosts:
+ - details
+ http:
+ - route:
+ - destination:
+ host: details
+ subset: v1
+---
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-details-v2.yaml b/Istio-Samples/bookinfo/networking/virtual-service-details-v2.yaml
new file mode 100644
index 00000000..5f21fa53
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-details-v2.yaml
@@ -0,0 +1,12 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: details
+spec:
+ hosts:
+ - details
+ http:
+ - route:
+ - destination:
+ host: details
+ subset: v2
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-ratings-db.yaml b/Istio-Samples/bookinfo/networking/virtual-service-ratings-db.yaml
new file mode 100644
index 00000000..1698ec24
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-ratings-db.yaml
@@ -0,0 +1,26 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: reviews
+spec:
+ hosts:
+ - reviews
+ http:
+ - route:
+ - destination:
+ host: reviews
+ subset: v3
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: ratings
+spec:
+ hosts:
+ - ratings
+ http:
+ - route:
+ - destination:
+ host: ratings
+ subset: v2
+---
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-ratings-mysql-vm.yaml b/Istio-Samples/bookinfo/networking/virtual-service-ratings-mysql-vm.yaml
new file mode 100644
index 00000000..fdf88270
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-ratings-mysql-vm.yaml
@@ -0,0 +1,26 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: reviews
+spec:
+ hosts:
+ - reviews
+ http:
+ - route:
+ - destination:
+ host: reviews
+ subset: v3
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: ratings
+spec:
+ hosts:
+ - ratings
+ http:
+ - route:
+ - destination:
+ host: ratings
+ subset: v2-mysql-vm
+---
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-ratings-mysql.yaml b/Istio-Samples/bookinfo/networking/virtual-service-ratings-mysql.yaml
new file mode 100644
index 00000000..03a700ea
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-ratings-mysql.yaml
@@ -0,0 +1,26 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: reviews
+spec:
+ hosts:
+ - reviews
+ http:
+ - route:
+ - destination:
+ host: reviews
+ subset: v3
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: ratings
+spec:
+ hosts:
+ - ratings
+ http:
+ - route:
+ - destination:
+ host: ratings
+ subset: v2-mysql
+---
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml b/Istio-Samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml
new file mode 100644
index 00000000..51c6fe9c
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml
@@ -0,0 +1,25 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: ratings
+spec:
+ hosts:
+ - ratings
+ http:
+ - match:
+ - headers:
+ end-user:
+ exact: jason
+ fault:
+ abort:
+ percentage:
+ value: 100.0
+ httpStatus: 500
+ route:
+ - destination:
+ host: ratings
+ subset: v1
+ - route:
+ - destination:
+ host: ratings
+ subset: v1
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml b/Istio-Samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml
new file mode 100644
index 00000000..6c4e19da
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml
@@ -0,0 +1,25 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: ratings
+spec:
+ hosts:
+ - ratings
+ http:
+ - match:
+ - headers:
+ end-user:
+ exact: jason
+ fault:
+ delay:
+ percentage:
+ value: 100.0
+ fixedDelay: 7s
+ route:
+ - destination:
+ host: ratings
+ subset: v1
+ - route:
+ - destination:
+ host: ratings
+ subset: v1
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml b/Istio-Samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml
new file mode 100644
index 00000000..aad8c317
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml
@@ -0,0 +1,17 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: reviews
+spec:
+ hosts:
+ - reviews
+ http:
+ - route:
+ - destination:
+ host: reviews
+ subset: v1
+ weight: 50
+ - destination:
+ host: reviews
+ subset: v3
+ weight: 50
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-reviews-80-20.yaml b/Istio-Samples/bookinfo/networking/virtual-service-reviews-80-20.yaml
new file mode 100644
index 00000000..7304d867
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-reviews-80-20.yaml
@@ -0,0 +1,17 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: reviews
+spec:
+ hosts:
+ - reviews
+ http:
+ - route:
+ - destination:
+ host: reviews
+ subset: v1
+ weight: 80
+ - destination:
+ host: reviews
+ subset: v2
+ weight: 20
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-reviews-90-10.yaml b/Istio-Samples/bookinfo/networking/virtual-service-reviews-90-10.yaml
new file mode 100644
index 00000000..d211dd16
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-reviews-90-10.yaml
@@ -0,0 +1,17 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: reviews
+spec:
+ hosts:
+ - reviews
+ http:
+ - route:
+ - destination:
+ host: reviews
+ subset: v1
+ weight: 90
+ - destination:
+ host: reviews
+ subset: v2
+ weight: 10
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml b/Istio-Samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml
new file mode 100644
index 00000000..fb357136
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml
@@ -0,0 +1,20 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: reviews
+spec:
+ hosts:
+ - reviews
+ http:
+ - match:
+ - headers:
+ end-user:
+ exact: jason
+ route:
+ - destination:
+ host: reviews
+ subset: v2
+ - route:
+ - destination:
+ host: reviews
+ subset: v3
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml b/Istio-Samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
new file mode 100644
index 00000000..ea07efb2
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
@@ -0,0 +1,20 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: reviews
+spec:
+ hosts:
+ - reviews
+ http:
+ - match:
+ - headers:
+ end-user:
+ exact: jason
+ route:
+ - destination:
+ host: reviews
+ subset: v2
+ - route:
+ - destination:
+ host: reviews
+ subset: v1
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-reviews-v2-v3.yaml b/Istio-Samples/bookinfo/networking/virtual-service-reviews-v2-v3.yaml
new file mode 100644
index 00000000..7ae7b804
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-reviews-v2-v3.yaml
@@ -0,0 +1,17 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: reviews
+spec:
+ hosts:
+ - reviews
+ http:
+ - route:
+ - destination:
+ host: reviews
+ subset: v2
+ weight: 50
+ - destination:
+ host: reviews
+ subset: v3
+ weight: 50
diff --git a/Istio-Samples/bookinfo/networking/virtual-service-reviews-v3.yaml b/Istio-Samples/bookinfo/networking/virtual-service-reviews-v3.yaml
new file mode 100644
index 00000000..5da999d4
--- /dev/null
+++ b/Istio-Samples/bookinfo/networking/virtual-service-reviews-v3.yaml
@@ -0,0 +1,12 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: reviews
+spec:
+ hosts:
+ - reviews
+ http:
+ - route:
+ - destination:
+ host: reviews
+ subset: v3
diff --git a/Istio-Samples/bookinfo/platform/kube/README.md b/Istio-Samples/bookinfo/platform/kube/README.md
new file mode 100644
index 00000000..d1189bec
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/README.md
@@ -0,0 +1,2 @@
+See the [Bookinfo guide](https://istio.io/docs/guides/bookinfo.html) in Istio
+docs for instructions on how to run this demo application.
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-certificate.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-certificate.yaml
new file mode 100644
index 00000000..bce874dc
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-certificate.yaml
@@ -0,0 +1,37 @@
+---
+apiVersion: certmanager.k8s.io/v1alpha1
+kind: ClusterIssuer
+metadata:
+ name: letsencrypt-staging
+ namespace: istio-system
+spec:
+ acme:
+ # The ACME server URL
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ # Email address used for ACME registration
+ email: stage@istio.io
+ # Name of a secret used to store the ACME account private key
+ privateKeySecretRef:
+ name: letsencrypt-staging
+ # Enable the HTTP-01 challenge provider
+ http01: {}
+---
+apiVersion: certmanager.k8s.io/v1alpha1
+kind: Certificate
+metadata:
+ name: istio-ingressgateway-certs
+ namespace: istio-system
+spec:
+ secretName: istio-ingressgateway-certs
+ issuerRef:
+ name: letsencrypt-staging
+ kind: ClusterIssuer
+ commonName: bookinfo.example.com
+ dnsNames:
+ - bookinfo.example.com
+ acme:
+ config:
+ - http01:
+ ingressClass: none
+ domains:
+ - bookinfo.example.com
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-db.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-db.yaml
new file mode 100644
index 00000000..1185c165
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-db.yaml
@@ -0,0 +1,60 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: mongodb
+ labels:
+ app: mongodb
+ service: mongodb
+spec:
+ ports:
+ - port: 27017
+ name: mongo
+ selector:
+ app: mongodb
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: mongodb-v1
+ labels:
+ app: mongodb
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: mongodb
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: mongodb
+ version: v1
+ spec:
+ containers:
+ - name: mongodb
+ image: docker.io/istio/examples-bookinfo-mongodb:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 27017
+ volumeMounts:
+ - name: data-db
+ mountPath: /data/db
+ volumes:
+ - name: data-db
+ emptyDir: {}
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-details-dualstack.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-details-dualstack.yaml
new file mode 100644
index 00000000..65241c9f
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-details-dualstack.yaml
@@ -0,0 +1,59 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Details service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: details
+ labels:
+ app: details
+ service: details
+spec:
+ ipFamilyPolicy: RequireDualStack
+ ipFamilies: [IPv6, IPv4]
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: details
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: details-v1
+ labels:
+ app: details
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: details
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: details
+ version: v1
+ spec:
+ containers:
+ - name: details
+ image: docker.io/istio/examples-bookinfo-details-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-details-v2.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-details-v2.yaml
new file mode 100644
index 00000000..bfcfe11c
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-details-v2.yaml
@@ -0,0 +1,46 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Details service v2
+##################################################################################################
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: details-v2
+ labels:
+ app: details
+ version: v2
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: details
+ version: v2
+ template:
+ metadata:
+ labels:
+ app: details
+ version: v2
+ spec:
+ containers:
+ - name: details
+ image: docker.io/istio/examples-bookinfo-details-v2:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+ env:
+ - name: DO_NOT_ENCRYPT
+ value: "true"
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-details.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-details.yaml
new file mode 100644
index 00000000..420f39f0
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-details.yaml
@@ -0,0 +1,57 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Details service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: details
+ labels:
+ app: details
+ service: details
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: details
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: details-v1
+ labels:
+ app: details
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: details
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: details
+ version: v1
+ spec:
+ containers:
+ - name: details
+ image: docker.io/istio/examples-bookinfo-details-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-dualstack.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-dualstack.yaml
new file mode 100644
index 00000000..5d920dff
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-dualstack.yaml
@@ -0,0 +1,343 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# This file defines the services, service accounts, and deployments for the Bookinfo sample.
+#
+# To apply all 4 Bookinfo services, their corresponding service accounts, and deployments:
+#
+# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
+#
+# Alternatively, you can deploy any resource separately:
+#
+# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l service=reviews # reviews Service
+# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l account=reviews # reviews ServiceAccount
+# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l app=reviews,version=v3 # reviews-v3 Deployment
+##################################################################################################
+
+##################################################################################################
+# Details service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: details
+ labels:
+ app: details
+ service: details
+spec:
+ ipFamilyPolicy: RequireDualStack
+ ipFamilies: [IPv6, IPv4]
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: details
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-details
+ labels:
+ account: details
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: details-v1
+ labels:
+ app: details
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: details
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: details
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-details
+ containers:
+ - name: details
+ image: docker.io/istio/examples-bookinfo-details-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+---
+##################################################################################################
+# Ratings service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: ratings
+ labels:
+ app: ratings
+ service: ratings
+spec:
+ ipFamilyPolicy: RequireDualStack
+ ipFamilies: [IPv6, IPv4]
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: ratings
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-ratings
+ labels:
+ account: ratings
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: ratings-v1
+ labels:
+ app: ratings
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ratings
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: ratings
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-ratings
+ containers:
+ - name: ratings
+ image: docker.io/istio/examples-bookinfo-ratings-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+---
+##################################################################################################
+# Reviews service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: reviews
+ labels:
+ app: reviews
+ service: reviews
+spec:
+ ipFamilyPolicy: RequireDualStack
+ ipFamilies: [IPv4, IPv6]
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: reviews
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-reviews
+ labels:
+ account: reviews
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v1
+ labels:
+ app: reviews
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-reviews
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v2
+ labels:
+ app: reviews
+ version: v2
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v2
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v2
+ spec:
+ serviceAccountName: bookinfo-reviews
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v2:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v3
+ labels:
+ app: reviews
+ version: v3
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v3
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v3
+ spec:
+ serviceAccountName: bookinfo-reviews
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v3:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
+---
+##################################################################################################
+# Productpage services
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: productpage
+ labels:
+ app: productpage
+ service: productpage
+spec:
+ ipFamilyPolicy: RequireDualStack
+ ipFamilies: [IPv4, IPv6]
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: productpage
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-productpage
+ labels:
+ account: productpage
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: productpage-v1
+ labels:
+ app: productpage
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: productpage
+ version: v1
+ template:
+ metadata:
+ annotations:
+ prometheus.io/scrape: "true"
+ prometheus.io/port: "9080"
+ prometheus.io/path: "/metrics"
+ labels:
+ app: productpage
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-productpage
+ containers:
+ - name: productpage
+ image: docker.io/istio/examples-bookinfo-productpage-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ volumes:
+ - name: tmp
+ emptyDir: {}
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-ingress.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-ingress.yaml
new file mode 100644
index 00000000..e2143399
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-ingress.yaml
@@ -0,0 +1,63 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+###########################################################################
+# Ingress resource (gateway)
+##########################################################################
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: gateway
+ annotations:
+ kubernetes.io/ingress.class: "istio"
+spec:
+ rules:
+ - http:
+ paths:
+ - path: /productpage
+ pathType: Exact
+ backend:
+ service:
+ name: productpage
+ port:
+ number: 9080
+ - path: /static/
+ pathType: Prefix
+ backend:
+ service:
+ name: productpage
+ port:
+ number: 9080
+ - path: /login
+ pathType: Exact
+ backend:
+ service:
+ name: productpage
+ port:
+ number: 9080
+ - path: /logout
+ pathType: Exact
+ backend:
+ service:
+ name: productpage
+ port:
+ number: 9080
+ - path: /api/v1/products
+ pathType: Prefix
+ backend:
+ service:
+ name: productpage
+ port:
+ number: 9080
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-mysql.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-mysql.yaml
new file mode 100644
index 00000000..c26bd6fd
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-mysql.yaml
@@ -0,0 +1,79 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Mysql db services
+# credentials: root/password
+##################################################################################################
+apiVersion: v1
+kind: Secret
+metadata:
+ name: mysql-credentials
+type: Opaque
+data:
+ rootpasswd: cGFzc3dvcmQ=
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: mysqldb
+ labels:
+ app: mysqldb
+ service: mysqldb
+spec:
+ ports:
+ - port: 3306
+ name: tcp
+ selector:
+ app: mysqldb
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: mysqldb-v1
+ labels:
+ app: mysqldb
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: mysqldb
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: mysqldb
+ version: v1
+ spec:
+ containers:
+ - name: mysqldb
+ image: docker.io/istio/examples-bookinfo-mysqldb:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 3306
+ env:
+ - name: MYSQL_ROOT_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: mysql-credentials
+ key: rootpasswd
+ args: ["--default-authentication-plugin","mysql_native_password"]
+ volumeMounts:
+ - name: var-lib-mysql
+ mountPath: /var/lib/mysql
+ volumes:
+ - name: var-lib-mysql
+ emptyDir: {}
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-psa.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-psa.yaml
new file mode 100644
index 00000000..13c34e08
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-psa.yaml
@@ -0,0 +1,363 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# This file defines the same services, service accounts, and deployments as bookinfo.yaml with
+# added securityContext fields to allow the bookinfo demo to run on a PodSecurityAdmission
+# enabled cluster that enforces the baseline policy.
+##################################################################################################
+
+##################################################################################################
+# Details service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: details
+ labels:
+ app: details
+ service: details
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: details
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-details
+ labels:
+ account: details
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: details-v1
+ labels:
+ app: details
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: details
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: details
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-details
+ containers:
+ - name: details
+ image: docker.io/istio/examples-bookinfo-details-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - all
+ runAsNonRoot: true
+---
+##################################################################################################
+# Ratings service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: ratings
+ labels:
+ app: ratings
+ service: ratings
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: ratings
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-ratings
+ labels:
+ account: ratings
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: ratings-v1
+ labels:
+ app: ratings
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ratings
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: ratings
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-ratings
+ containers:
+ - name: ratings
+ image: docker.io/istio/examples-bookinfo-ratings-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - all
+ runAsNonRoot: true
+---
+##################################################################################################
+# Reviews service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: reviews
+ labels:
+ app: reviews
+ service: reviews
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: reviews
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-reviews
+ labels:
+ account: reviews
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v1
+ labels:
+ app: reviews
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-reviews
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - all
+ runAsNonRoot: true
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v2
+ labels:
+ app: reviews
+ version: v2
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v2
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v2
+ spec:
+ serviceAccountName: bookinfo-reviews
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v2:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - all
+ runAsNonRoot: true
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v3
+ labels:
+ app: reviews
+ version: v3
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v3
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v3
+ spec:
+ serviceAccountName: bookinfo-reviews
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v3:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - all
+ runAsNonRoot: true
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
+---
+##################################################################################################
+# Productpage services
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: productpage
+ labels:
+ app: productpage
+ service: productpage
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: productpage
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-productpage
+ labels:
+ account: productpage
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: productpage-v1
+ labels:
+ app: productpage
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: productpage
+ version: v1
+ template:
+ metadata:
+ annotations:
+ prometheus.io/scrape: "true"
+ prometheus.io/port: "9080"
+ prometheus.io/path: "/metrics"
+ labels:
+ app: productpage
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-productpage
+ containers:
+ - name: productpage
+ image: docker.io/istio/examples-bookinfo-productpage-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - all
+ runAsNonRoot: true
+ volumes:
+ - name: tmp
+ emptyDir: {}
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-discovery-dualstack.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-discovery-dualstack.yaml
new file mode 100644
index 00000000..c8364636
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-discovery-dualstack.yaml
@@ -0,0 +1,33 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Ratings service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: ratings
+ labels:
+ app: ratings
+ service: ratings
+spec:
+ ipFamilyPolicy: RequireDualStack
+ ipFamilies: [IPv6, IPv4]
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: ratings
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-discovery.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-discovery.yaml
new file mode 100644
index 00000000..61c4b7f1
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-discovery.yaml
@@ -0,0 +1,31 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Ratings service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: ratings
+ labels:
+ app: ratings
+ service: ratings
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: ratings
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-dualstack.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-dualstack.yaml
new file mode 100644
index 00000000..9671b229
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-dualstack.yaml
@@ -0,0 +1,59 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Ratings service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: ratings
+ labels:
+ app: ratings
+ service: ratings
+spec:
+ ipFamilyPolicy: RequireDualStack
+ ipFamilies: [IPv6, IPv4]
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: ratings
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: ratings-v1
+ labels:
+ app: ratings
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ratings
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: ratings
+ version: v1
+ spec:
+ containers:
+ - name: ratings
+ image: docker.io/istio/examples-bookinfo-ratings-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql-vm.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql-vm.yaml
new file mode 100644
index 00000000..c65e6d20
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql-vm.yaml
@@ -0,0 +1,53 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: ratings-v2-mysql-vm
+ labels:
+ app: ratings
+ version: v2-mysql-vm
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ratings
+ version: v2-mysql-vm
+ template:
+ metadata:
+ labels:
+ app: ratings
+ version: v2-mysql-vm
+ spec:
+ containers:
+ - name: ratings
+ image: docker.io/istio/examples-bookinfo-ratings-v2:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ # This assumes you registered your mysql vm as
+ # istioctl register -n vm mysqldb 1.2.3.4 3306
+ - name: DB_TYPE
+ value: "mysql"
+ - name: MYSQL_DB_HOST
+ value: mysqldb.vm.svc.cluster.local
+ - name: MYSQL_DB_PORT
+ value: "3306"
+ - name: MYSQL_DB_USER
+ value: root
+ - name: MYSQL_DB_PASSWORD
+ value: password
+ ports:
+ - containerPort: 9080
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml
new file mode 100644
index 00000000..f1b252d5
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml
@@ -0,0 +1,56 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: ratings-v2-mysql
+ labels:
+ app: ratings
+ version: v2-mysql
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ratings
+ version: v2-mysql
+ template:
+ metadata:
+ labels:
+ app: ratings
+ version: v2-mysql
+ spec:
+ containers:
+ - name: ratings
+ image: docker.io/istio/examples-bookinfo-ratings-v2:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ # ratings-v2 will use mongodb as the default db backend.
+ # if you would like to use mysqldb then you can use this file
+ # which sets DB_TYPE = 'mysql' and the rest of the parameters shown
+ # here and also create the # mysqldb service using bookinfo-mysql.yaml
+ # NOTE: This file is mutually exclusive to bookinfo-ratings-v2.yaml
+ - name: DB_TYPE
+ value: "mysql"
+ - name: MYSQL_DB_HOST
+ value: mysqldb
+ - name: MYSQL_DB_PORT
+ value: "3306"
+ - name: MYSQL_DB_USER
+ value: root
+ - name: MYSQL_DB_PASSWORD
+ value: password
+ ports:
+ - containerPort: 9080
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml
new file mode 100644
index 00000000..a223d75d
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml
@@ -0,0 +1,63 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-ratings-v2
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: ratings-v2
+ labels:
+ app: ratings
+ version: v2
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ratings
+ version: v2
+ template:
+ metadata:
+ labels:
+ app: ratings
+ version: v2
+ spec:
+ serviceAccountName: bookinfo-ratings-v2
+ containers:
+ - name: ratings
+ image: docker.io/istio/examples-bookinfo-ratings-v2:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ # ratings-v2 will use mongodb as the default db backend.
+ # if you would like to use mysqldb then set DB_TYPE = 'mysql', set
+ # the rest of the parameters shown here and also create the
+ # mysqldb service using bookinfo-mysql.yaml
+ # - name: DB_TYPE #default to
+ # value: "mysql"
+ # - name: MYSQL_DB_HOST
+ # value: mysqldb
+ # - name: MYSQL_DB_PORT
+ # value: "3306"
+ # - name: MYSQL_DB_USER
+ # value: root
+ # - name: MYSQL_DB_PASSWORD
+ # value: password
+ - name: MONGO_DB_URL
+ value: mongodb://mongodb:27017/test
+ ports:
+ - containerPort: 9080
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings.yaml
new file mode 100644
index 00000000..49ead717
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-ratings.yaml
@@ -0,0 +1,57 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Ratings service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: ratings
+ labels:
+ app: ratings
+ service: ratings
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: ratings
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: ratings-v1
+ labels:
+ app: ratings
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ratings
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: ratings
+ version: v1
+ spec:
+ containers:
+ - name: ratings
+ image: docker.io/istio/examples-bookinfo-ratings-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-reviews-v2.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-reviews-v2.yaml
new file mode 100644
index 00000000..71bb24c4
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-reviews-v2.yaml
@@ -0,0 +1,56 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Reviews service v2
+##################################################################################################
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v2
+ labels:
+ app: reviews
+ version: v2
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v2
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v2
+ spec:
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v2:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo-versions.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo-versions.yaml
new file mode 100644
index 00000000..c374bbee
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo-versions.yaml
@@ -0,0 +1,72 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: reviews-v1
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: reviews
+ version: v1
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: reviews-v2
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: reviews
+ version: v2
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: reviews-v3
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: reviews
+ version: v3
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: productpage-v1
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: productpage
+ version: v1
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: ratings-v1
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: ratings
+ version: v1
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: details-v1
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: details
+ version: v1
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/bookinfo.yaml b/Istio-Samples/bookinfo/platform/kube/bookinfo.yaml
new file mode 100644
index 00000000..1367862c
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/bookinfo.yaml
@@ -0,0 +1,335 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# This file defines the services, service accounts, and deployments for the Bookinfo sample.
+#
+# To apply all 4 Bookinfo services, their corresponding service accounts, and deployments:
+#
+# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
+#
+# Alternatively, you can deploy any resource separately:
+#
+# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l service=reviews # reviews Service
+# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l account=reviews # reviews ServiceAccount
+# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l app=reviews,version=v3 # reviews-v3 Deployment
+##################################################################################################
+
+##################################################################################################
+# Details service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: details
+ labels:
+ app: details
+ service: details
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: details
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-details
+ labels:
+ account: details
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: details-v1
+ labels:
+ app: details
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: details
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: details
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-details
+ containers:
+ - name: details
+ image: docker.io/istio/examples-bookinfo-details-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+---
+##################################################################################################
+# Ratings service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: ratings
+ labels:
+ app: ratings
+ service: ratings
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: ratings
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-ratings
+ labels:
+ account: ratings
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: ratings-v1
+ labels:
+ app: ratings
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ratings
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: ratings
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-ratings
+ containers:
+ - name: ratings
+ image: docker.io/istio/examples-bookinfo-ratings-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+---
+##################################################################################################
+# Reviews service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: reviews
+ labels:
+ app: reviews
+ service: reviews
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: reviews
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-reviews
+ labels:
+ account: reviews
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v1
+ labels:
+ app: reviews
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-reviews
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v2
+ labels:
+ app: reviews
+ version: v2
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v2
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v2
+ spec:
+ serviceAccountName: bookinfo-reviews
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v2:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reviews-v3
+ labels:
+ app: reviews
+ version: v3
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: reviews
+ version: v3
+ template:
+ metadata:
+ labels:
+ app: reviews
+ version: v3
+ spec:
+ serviceAccountName: bookinfo-reviews
+ containers:
+ - name: reviews
+ image: docker.io/istio/examples-bookinfo-reviews-v3:1.18.0
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: LOG_DIR
+ value: "/tmp/logs"
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ - name: wlp-output
+ mountPath: /opt/ibm/wlp/output
+ volumes:
+ - name: wlp-output
+ emptyDir: {}
+ - name: tmp
+ emptyDir: {}
+---
+##################################################################################################
+# Productpage services
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: productpage
+ labels:
+ app: productpage
+ service: productpage
+spec:
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: productpage
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bookinfo-productpage
+ labels:
+ account: productpage
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: productpage-v1
+ labels:
+ app: productpage
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: productpage
+ version: v1
+ template:
+ metadata:
+ annotations:
+ prometheus.io/scrape: "true"
+ prometheus.io/port: "9080"
+ prometheus.io/path: "/metrics"
+ labels:
+ app: productpage
+ version: v1
+ spec:
+ serviceAccountName: bookinfo-productpage
+ containers:
+ - name: productpage
+ image: docker.io/istio/examples-bookinfo-productpage-v1:1.18.0
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 9080
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ volumes:
+ - name: tmp
+ emptyDir: {}
+---
diff --git a/Istio-Samples/bookinfo/platform/kube/cleanup.sh b/Istio-Samples/bookinfo/platform/kube/cleanup.sh
new file mode 100755
index 00000000..bdf700d1
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/cleanup.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+#
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+
+# only ask if in interactive mode
+if [[ -t 0 && -z ${NAMESPACE} ]];then
+ echo -n "namespace ? [default] "
+ read -r NAMESPACE
+fi
+
+# verify if the namespace exists, otherwise use default namespace
+if [[ -n ${NAMESPACE} ]];then
+ ns=$(kubectl get namespace "${NAMESPACE}" --no-headers --output=go-template="{{.metadata.name}}" 2>/dev/null)
+ if [[ -z ${ns} ]];then
+ echo "NAMESPACE ${NAMESPACE} not found."
+ NAMESPACE=default
+ fi
+fi
+
+# if no namespace is provided, use default namespace
+if [[ -z ${NAMESPACE} ]];then
+ NAMESPACE=default
+fi
+
+echo "using NAMESPACE=${NAMESPACE}"
+
+# clean up Istio traffic management resources that may have been used
+protos=( destinationrules virtualservices gateways )
+for proto in "${protos[@]}"; do
+ for resource in $(kubectl get -n "${NAMESPACE}" "$proto" -o name); do
+ kubectl delete -n "${NAMESPACE}" "$resource";
+ done
+done
+
+# clean up Gateway API resources that may have been used
+if kubectl get crd gateways.gateway.networking.k8s.io >/dev/null 2>&1; then
+ protos=( httproutes gateways.gateway.networking.k8s.io )
+ for proto in "${protos[@]}"; do
+ for resource in $(kubectl get -n "${NAMESPACE}" "$proto" -o name); do
+ kubectl delete -n "${NAMESPACE}" "$resource";
+ done
+ done
+ kubectl delete -n "${NAMESPACE}" -f "$SCRIPTDIR/bookinfo-versions.yaml" >/dev/null 2>&1
+fi
+
+OUTPUT=$(mktemp)
+export OUTPUT
+echo "Application cleanup may take up to one minute"
+kubectl delete -n "${NAMESPACE}" -f "$SCRIPTDIR/bookinfo.yaml" > "${OUTPUT}" 2>&1
+ret=$?
+function cleanup() {
+ rm -f "${OUTPUT}"
+}
+
+trap cleanup EXIT
+
+if [[ ${ret} -eq 0 ]];then
+ cat "${OUTPUT}"
+else
+ # ignore NotFound errors
+ OUT2=$(grep -v NotFound "${OUTPUT}")
+ if [[ -n ${OUT2} ]];then
+ cat "${OUTPUT}"
+ exit ${ret}
+ fi
+fi
+
+# wait for 30 sec for bookinfo to clean up
+sleep 30
+
+echo "Application cleanup successful"
diff --git a/Istio-Samples/bookinfo/platform/kube/productpage-nodeport.yaml b/Istio-Samples/bookinfo/platform/kube/productpage-nodeport.yaml
new file mode 100644
index 00000000..aadba2e0
--- /dev/null
+++ b/Istio-Samples/bookinfo/platform/kube/productpage-nodeport.yaml
@@ -0,0 +1,32 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Productpage services
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: productpage
+ labels:
+ app: productpage
+ service: productpage
+spec:
+ type: NodePort
+ ports:
+ - port: 9080
+ name: http
+ selector:
+ app: productpage
+---
diff --git a/Istio-Samples/bookinfo/policy/productpage_envoy_ratelimit.yaml b/Istio-Samples/bookinfo/policy/productpage_envoy_ratelimit.yaml
new file mode 100644
index 00000000..ef96dc56
--- /dev/null
+++ b/Istio-Samples/bookinfo/policy/productpage_envoy_ratelimit.yaml
@@ -0,0 +1,88 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: EnvoyFilter
+metadata:
+ name: filter-ratelimit
+ namespace: istio-system
+spec:
+ workloadSelector:
+ # select by label in the same namespace
+ labels:
+ istio: ingressgateway
+ configPatches:
+ # The Envoy config you want to modify
+ - applyTo: HTTP_FILTER
+ match:
+ context: GATEWAY
+ listener:
+ filterChain:
+ filter:
+ name: "envoy.filters.network.http_connection_manager"
+ subFilter:
+ name: "envoy.filters.http.router"
+ patch:
+ operation: INSERT_BEFORE
+ value:
+ name: envoy.ratelimit
+ typed_config:
+ "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
+ # domain can be anything! Match it to the ratelimter service config
+ domain: productpage-ratelimit
+ failure_mode_deny: true
+ rate_limit_service:
+ grpc_service:
+ envoy_grpc:
+ cluster_name: rate_limit_cluster
+ timeout: 10s
+ - applyTo: CLUSTER
+ match:
+ cluster:
+ service: ratelimit.default.svc.cluster.local
+ patch:
+ operation: ADD
+ value:
+ name: rate_limit_cluster
+ type: STRICT_DNS
+ connect_timeout: 10s
+ lb_policy: ROUND_ROBIN
+ http2_protocol_options: {}
+ load_assignment:
+ cluster_name: rate_limit_cluster
+ endpoints:
+ - lb_endpoints:
+ - endpoint:
+ address:
+ socket_address:
+ address: ratelimit.default.svc.cluster.local
+ port_value: 8081
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: EnvoyFilter
+metadata:
+ name: filter-ratelimit-svc
+ namespace: istio-system
+spec:
+ workloadSelector:
+ labels:
+ istio: ingressgateway
+ configPatches:
+ - applyTo: VIRTUAL_HOST
+ match:
+ context: GATEWAY
+ routeConfiguration:
+ vhost:
+ name: ""
+ route:
+ action: ANY
+ patch:
+ operation: MERGE
+ value:
+ rate_limits:
+ - actions: # any actions in here
+ # Multiple actions nest the descriptors
+ # - generic_key:
+ # descriptor_value: "test"
+ - request_headers:
+ header_name: ":path"
+ descriptor_key: "PATH"
+ # - remote_address: {}
+ # - destination_cluster: {}
\ No newline at end of file
diff --git a/Istio-Samples/bookinfo/src/build-services.sh b/Istio-Samples/bookinfo/src/build-services.sh
new file mode 100755
index 00000000..087d0279
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/build-services.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ox errexit
+
+# Get to the root directory of the repo...
+SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+cd "$SCRIPTDIR/../../.."
+
+h="${BOOKINFO_HUB:?BOOKINFO_HUB must be set}"
+t="${BOOKINFO_TAG:?BOOKINFO_TAG must be set}"
+if [[ ("${h}" == "istio" || "${h}" == "docker.io/istio") && -z "$CI" && "$*" =~ "--push" ]]; then
+ echo "Can only push to prod registry in CI"
+ exit 1
+fi
+
+plat="linux/amd64"
+if [[ "${MULTI_ARCH}" == "true" ]]; then
+ plat="linux/amd64,linux/arm64"
+fi
+
+# Pass input args to the command. This allows using --push, --load, etc
+env TAG="${BOOKINFO_TAG}" HUB="${BOOKINFO_HUB}" \
+ docker buildx bake -f samples/bookinfo/src/docker-bake.hcl --set "*.platform=${plat}" "$@"
+
+if [[ "${BOOKINFO_UPDATE}" == "true" ]]; then
+# Update image references in the yaml files
+ find ./samples/bookinfo/platform -name "*bookinfo*.yaml" -exec sed -i.bak "s#image:.*\\(\\/examples-bookinfo-.*\\):.*#image: ${h//\//\\/}\\1:$t#g" {} +
+fi
+
diff --git a/Istio-Samples/bookinfo/src/details/Dockerfile b/Istio-Samples/bookinfo/src/details/Dockerfile
new file mode 100644
index 00000000..77f8b429
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/details/Dockerfile
@@ -0,0 +1,29 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM ruby:2.7.1-slim
+
+COPY details.rb /opt/microservices/
+
+ARG service_version
+ENV SERVICE_VERSION ${service_version:-v1}
+ARG enable_external_book_service
+ENV ENABLE_EXTERNAL_BOOK_SERVICE ${enable_external_book_service:-false}
+
+EXPOSE 9080
+WORKDIR /opt/microservices
+
+CMD ["ruby", "details.rb", "9080"]
+
+USER 1000
diff --git a/Istio-Samples/bookinfo/src/details/details.rb b/Istio-Samples/bookinfo/src/details/details.rb
new file mode 100755
index 00000000..38911abd
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/details/details.rb
@@ -0,0 +1,197 @@
+#!/usr/bin/ruby
+#
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'webrick'
+require 'json'
+require 'net/http'
+
+if ARGV.length < 1 then
+ puts "usage: #{$PROGRAM_NAME} port"
+ exit(-1)
+end
+
+port = Integer(ARGV[0])
+
+server = WEBrick::HTTPServer.new :BindAddress => '*', :Port => port
+
+trap 'INT' do server.shutdown end
+
+server.mount_proc '/health' do |req, res|
+ res.status = 200
+ res.body = {'status' => 'Details is healthy'}.to_json
+ res['Content-Type'] = 'application/json'
+end
+
+server.mount_proc '/details' do |req, res|
+ pathParts = req.path.split('/')
+ headers = get_forward_headers(req)
+
+ begin
+ begin
+ id = Integer(pathParts[-1])
+ rescue
+ raise 'please provide numeric product id'
+ end
+ details = get_book_details(id, headers)
+ res.body = details.to_json
+ res['Content-Type'] = 'application/json'
+ rescue => error
+ res.body = {'error' => error}.to_json
+ res['Content-Type'] = 'application/json'
+ res.status = 400
+ end
+end
+
+# TODO: provide details on different books.
+def get_book_details(id, headers)
+ if ENV['ENABLE_EXTERNAL_BOOK_SERVICE'] === 'true' then
+ # the ISBN of one of Comedy of Errors on the Amazon
+ # that has Shakespeare as the single author
+ isbn = '0486424618'
+ return fetch_details_from_external_service(isbn, id, headers)
+ end
+
+ return {
+ 'id' => id,
+ 'author': 'William Shakespeare',
+ 'year': 1595,
+ 'type' => 'paperback',
+ 'pages' => 200,
+ 'publisher' => 'PublisherA',
+ 'language' => 'English',
+ 'ISBN-10' => '1234567890',
+ 'ISBN-13' => '123-1234567890'
+ }
+end
+
+def fetch_details_from_external_service(isbn, id, headers)
+ uri = URI.parse('https://www.googleapis.com/books/v1/volumes?q=isbn:' + isbn)
+ http = Net::HTTP.new(uri.host, ENV['DO_NOT_ENCRYPT'] === 'true' ? 80:443)
+ http.read_timeout = 5 # seconds
+
+ # DO_NOT_ENCRYPT is used to configure the details service to use either
+ # HTTP (true) or HTTPS (false, default) when calling the external service to
+ # retrieve the book information.
+ #
+ # Unless this environment variable is set to true, the app will use TLS (HTTPS)
+ # to access external services.
+ unless ENV['DO_NOT_ENCRYPT'] === 'true' then
+ http.use_ssl = true
+ end
+
+ request = Net::HTTP::Get.new(uri.request_uri)
+ headers.each { |header, value| request[header] = value }
+
+ response = http.request(request)
+
+ json = JSON.parse(response.body)
+ book = json['items'][0]['volumeInfo']
+
+ language = book['language'] === 'en'? 'English' : 'unknown'
+ type = book['printType'] === 'BOOK'? 'paperback' : 'unknown'
+ isbn10 = get_isbn(book, 'ISBN_10')
+ isbn13 = get_isbn(book, 'ISBN_13')
+
+ return {
+ 'id' => id,
+ 'author': book['authors'][0],
+ 'year': book['publishedDate'],
+ 'type' => type,
+ 'pages' => book['pageCount'],
+ 'publisher' => book['publisher'],
+ 'language' => language,
+ 'ISBN-10' => isbn10,
+ 'ISBN-13' => isbn13
+ }
+
+end
+
+def get_isbn(book, isbn_type)
+ isbn_dentifiers = book['industryIdentifiers'].select do |identifier|
+ identifier['type'] === isbn_type
+ end
+
+ return isbn_dentifiers[0]['identifier']
+end
+
+def get_forward_headers(request)
+ headers = {}
+
+ # Keep this in sync with the headers in productpage and reviews.
+ incoming_headers = [
+ # All applications should propagate x-request-id. This header is
+ # included in access log statements and is used for consistent trace
+ # sampling and log sampling decisions in Istio.
+ 'x-request-id',
+
+ # Lightstep tracing header. Propagate this if you use lightstep tracing
+ # in Istio (see
+ # https://istio.io/latest/docs/tasks/observability/distributed-tracing/lightstep/)
+ # Note: this should probably be changed to use B3 or W3C TRACE_CONTEXT.
+ # Lightstep recommends using B3 or TRACE_CONTEXT and most application
+ # libraries from lightstep do not support x-ot-span-context.
+ 'x-ot-span-context',
+
+ # Datadog tracing header. Propagate these headers if you use Datadog
+ # tracing.
+ 'x-datadog-trace-id',
+ 'x-datadog-parent-id',
+ 'x-datadog-sampling-priority',
+
+ # W3C Trace Context. Compatible with OpenCensusAgent and Stackdriver Istio
+ # configurations.
+ 'traceparent',
+ 'tracestate',
+
+ # Cloud trace context. Compatible with OpenCensusAgent and Stackdriver Istio
+ # configurations.
+ 'x-cloud-trace-context',
+
+ # Grpc binary trace context. Compatible with OpenCensusAgent nad
+ # Stackdriver Istio configurations.
+ 'grpc-trace-bin',
+
+ # b3 trace headers. Compatible with Zipkin, OpenCensusAgent, and
+ # Stackdriver Istio configurations.
+ 'x-b3-traceid',
+ 'x-b3-spanid',
+ 'x-b3-parentspanid',
+ 'x-b3-sampled',
+ 'x-b3-flags',
+
+ # SkyWalking trace headers.
+ 'sw8',
+
+ # Application-specific headers to forward.
+ 'end-user',
+ 'user-agent',
+
+ # Context and session specific headers
+ 'cookie',
+ 'authorization',
+ 'jwt'
+ ]
+
+ request.each do |header, value|
+ if incoming_headers.include? header then
+ headers[header] = value
+ end
+ end
+
+ return headers
+end
+
+server.start
diff --git a/Istio-Samples/bookinfo/src/docker-bake.hcl b/Istio-Samples/bookinfo/src/docker-bake.hcl
new file mode 100644
index 00000000..6c7ac94b
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/docker-bake.hcl
@@ -0,0 +1,158 @@
+variable "TAG" {
+ default = "latest"
+}
+
+variable "HUB" {
+ default = "localhost:5000"
+}
+
+// TODO: in buildx 0.11 they have matrix build which will help this
+
+// Productpage
+target "examples-bookinfo-productpage-v1" {
+ tags = ["${HUB}/examples-bookinfo-productpage-v1:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ context = "./samples/bookinfo/src/productpage"
+}
+target "examples-bookinfo-productpage-v-flooding" {
+ tags = ["${HUB}/examples-bookinfo-productpage-v-flooding:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ args = {
+ flood_factor = 100
+ }
+ context = "./samples/bookinfo/src/productpage"
+}
+
+// Details
+target "examples-bookinfo-details-v1" {
+ tags = ["${HUB}/examples-bookinfo-details-v1:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ args = {
+ service_version = "v1"
+ }
+ context = "./samples/bookinfo/src/details"
+}
+target "examples-bookinfo-details-v2" {
+ tags = ["${HUB}/examples-bookinfo-details-v2:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ args = {
+ service_version = "v2"
+ enable_external_book_service = true
+ }
+ context = "./samples/bookinfo/src/details"
+}
+
+// Reviews
+target "examples-bookinfo-reviews-v1" {
+ tags = ["${HUB}/examples-bookinfo-reviews-v1:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ args = {
+ service_version = "v1"
+ }
+ context = "./samples/bookinfo/src/reviews"
+}
+target "examples-bookinfo-reviews-v2" {
+ tags = ["${HUB}/examples-bookinfo-reviews-v2:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ args = {
+ service_version = "v2"
+ enable_ratings = true
+ }
+ context = "./samples/bookinfo/src/reviews"
+}
+target "examples-bookinfo-reviews-v3" {
+ tags = ["${HUB}/examples-bookinfo-reviews-v3:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ args = {
+ service_version = "v3"
+ enable_ratings = true
+ star_color = "red"
+ }
+ context = "./samples/bookinfo/src/reviews"
+}
+
+// Ratings
+target "examples-bookinfo-ratings-v1" {
+ tags = ["${HUB}/examples-bookinfo-ratings-v1:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ args = {
+ service_version = "v1"
+ }
+ context = "./samples/bookinfo/src/ratings"
+}
+target "examples-bookinfo-ratings-v2" {
+ tags = ["${HUB}/examples-bookinfo-ratings-v2:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ args = {
+ service_version = "v2"
+ }
+ context = "./samples/bookinfo/src/ratings"
+}
+target "examples-bookinfo-ratings-v-faulty" {
+ tags = ["${HUB}/examples-bookinfo-ratings-v-faulty:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ args = {
+ service_version = "v-faulty"
+ }
+ context = "./samples/bookinfo/src/ratings"
+}
+target "examples-bookinfo-ratings-v-delayed" {
+ tags = ["${HUB}/examples-bookinfo-ratings-v-delayed:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ args = {
+ service_version = "v-delayed"
+ }
+ context = "./samples/bookinfo/src/ratings"
+}
+target "examples-bookinfo-ratings-v-unavailable" {
+ tags = ["${HUB}/examples-bookinfo-ratings-v-unavailable:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ args = {
+ service_version = "v-unavailable"
+ }
+ context = "./samples/bookinfo/src/ratings"
+}
+target "examples-bookinfo-ratings-v-unhealthy" {
+ tags = ["${HUB}/examples-bookinfo-ratings-v-unhealthy:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ args = {
+ service_version = "v-unhealthy"
+ }
+ context = "./samples/bookinfo/src/ratings"
+}
+
+// mysql
+target "examples-bookinfo-mysqldb" {
+ tags = ["${HUB}/examples-bookinfo-mysqldb:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ context = "./samples/bookinfo/src/mysql"
+}
+
+// mongo
+target "examples-bookinfo-mongodb" {
+ tags = ["${HUB}/examples-bookinfo-mongodb:${TAG}"]
+ platforms = ["linux/amd64", "linux/arm64"]
+ context = "./samples/bookinfo/src/mongodb"
+}
+
+
+// All targets
+group "default" {
+ targets = [
+ "examples-bookinfo-productpage-v1",
+ "examples-bookinfo-productpage-v-flooding",
+ "examples-bookinfo-details-v1",
+ "examples-bookinfo-details-v2",
+ "examples-bookinfo-reviews-v1",
+ "examples-bookinfo-reviews-v2",
+ "examples-bookinfo-reviews-v3",
+ "examples-bookinfo-ratings-v1",
+ "examples-bookinfo-ratings-v2",
+ "examples-bookinfo-ratings-v-faulty",
+ "examples-bookinfo-ratings-v-delayed",
+ "examples-bookinfo-ratings-v-unavailable",
+ "examples-bookinfo-ratings-v-unhealthy",
+ "examples-bookinfo-mysqldb",
+ "examples-bookinfo-mongodb",
+ ]
+}
diff --git a/Istio-Samples/bookinfo/src/mongodb/Dockerfile b/Istio-Samples/bookinfo/src/mongodb/Dockerfile
new file mode 100644
index 00000000..8737362f
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/mongodb/Dockerfile
@@ -0,0 +1,19 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM mongo:5.0.10
+WORKDIR /app/data/
+COPY ratings_data.json /app/data/
+COPY script.sh /docker-entrypoint-initdb.d/
+RUN chmod +x /docker-entrypoint-initdb.d/script.sh
diff --git a/Istio-Samples/bookinfo/src/mongodb/ratings_data.json b/Istio-Samples/bookinfo/src/mongodb/ratings_data.json
new file mode 100644
index 00000000..b4563b50
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/mongodb/ratings_data.json
@@ -0,0 +1,2 @@
+{rating: 5}
+{rating: 4}
diff --git a/Istio-Samples/bookinfo/src/mongodb/script.sh b/Istio-Samples/bookinfo/src/mongodb/script.sh
new file mode 100644
index 00000000..7e230ee5
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/mongodb/script.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+mongoimport --host localhost --db test --collection ratings --drop --file /app/data/ratings_data.json
diff --git a/Istio-Samples/bookinfo/src/mysql/Dockerfile b/Istio-Samples/bookinfo/src/mysql/Dockerfile
new file mode 100644
index 00000000..49141156
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/mysql/Dockerfile
@@ -0,0 +1,18 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM mysql:8.0.30
+# MYSQL_ROOT_PASSWORD must be supplied as an env var
+
+COPY ./mysqldb-init.sql /docker-entrypoint-initdb.d
diff --git a/Istio-Samples/bookinfo/src/mysql/mysqldb-init.sql b/Istio-Samples/bookinfo/src/mysql/mysqldb-init.sql
new file mode 100644
index 00000000..dea37e6f
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/mysql/mysqldb-init.sql
@@ -0,0 +1,13 @@
+# Initialize a mysql db with a 'test' db and be able test productpage with it.
+# mysql -h 127.0.0.1 -ppassword < mysqldb-init.sql
+
+CREATE DATABASE test;
+USE test;
+
+CREATE TABLE `ratings` (
+ `ReviewID` INT NOT NULL,
+ `Rating` INT,
+ PRIMARY KEY (`ReviewID`)
+);
+INSERT INTO ratings (ReviewID, Rating) VALUES (1, 5);
+INSERT INTO ratings (ReviewID, Rating) VALUES (2, 4);
diff --git a/Istio-Samples/bookinfo/src/productpage/Dockerfile b/Istio-Samples/bookinfo/src/productpage/Dockerfile
new file mode 100644
index 00000000..c1c5d352
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/Dockerfile
@@ -0,0 +1,40 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM python:3.7.7-slim
+
+WORKDIR /
+
+COPY requirements.txt ./
+RUN pip3 install -vvv --no-cache-dir -r requirements.txt
+
+COPY test-requirements.txt ./
+RUN pip3 install --no-cache-dir -r test-requirements.txt
+
+COPY productpage.py /opt/microservices/
+COPY tests/unit/* /opt/microservices/
+COPY templates /opt/microservices/templates
+COPY static /opt/microservices/static
+COPY requirements.txt /opt/microservices/
+
+ARG flood_factor
+ENV FLOOD_FACTOR ${flood_factor:-0}
+
+EXPOSE 9080
+WORKDIR /opt/microservices
+RUN python -m unittest discover
+
+CMD ["python", "productpage.py", "9080"]
+
+USER 1000
diff --git a/Istio-Samples/bookinfo/src/productpage/productpage.py b/Istio-Samples/bookinfo/src/productpage/productpage.py
new file mode 100755
index 00000000..ac9ec49c
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/productpage.py
@@ -0,0 +1,456 @@
+#!/usr/bin/python
+#
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+from __future__ import print_function
+from flask_bootstrap import Bootstrap
+from flask import Flask, request, session, render_template, redirect, url_for
+from flask import _request_ctx_stack as stack
+from jaeger_client import Tracer, ConstSampler
+from jaeger_client.reporter import NullReporter
+from jaeger_client.codecs import B3Codec
+from opentracing.ext import tags
+from opentracing.propagation import Format
+from opentracing_instrumentation.request_context import get_current_span, span_in_context
+from prometheus_client import Counter, generate_latest
+import simplejson as json
+import requests
+import sys
+from json2html import *
+import logging
+import os
+import asyncio
+
+# These two lines enable debugging at httplib level (requests->urllib3->http.client)
+# You will see the REQUEST, including HEADERS and DATA, and RESPONSE with HEADERS but without DATA.
+# The only thing missing will be the response.body which is not logged.
+try:
+ import http.client as http_client
+except ImportError:
+ # Python 2
+ import httplib as http_client
+http_client.HTTPConnection.debuglevel = 1
+
+app = Flask(__name__)
+logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
+requests_log = logging.getLogger("requests.packages.urllib3")
+requests_log.setLevel(logging.DEBUG)
+requests_log.propagate = True
+app.logger.addHandler(logging.StreamHandler(sys.stdout))
+app.logger.setLevel(logging.DEBUG)
+
+# Set the secret key to some random bytes. Keep this really secret!
+app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
+
+Bootstrap(app)
+
+servicesDomain = "" if (os.environ.get("SERVICES_DOMAIN") is None) else "." + os.environ.get("SERVICES_DOMAIN")
+detailsHostname = "details" if (os.environ.get("DETAILS_HOSTNAME") is None) else os.environ.get("DETAILS_HOSTNAME")
+detailsPort = "9080" if (os.environ.get("DETAILS_SERVICE_PORT") is None) else os.environ.get("DETAILS_SERVICE_PORT")
+ratingsHostname = "ratings" if (os.environ.get("RATINGS_HOSTNAME") is None) else os.environ.get("RATINGS_HOSTNAME")
+ratingsPort = "9080" if (os.environ.get("RATINGS_SERVICE_PORT") is None) else os.environ.get("RATINGS_SERVICE_PORT")
+reviewsHostname = "reviews" if (os.environ.get("REVIEWS_HOSTNAME") is None) else os.environ.get("REVIEWS_HOSTNAME")
+reviewsPort = "9080" if (os.environ.get("REVIEWS_SERVICE_PORT") is None) else os.environ.get("REVIEWS_SERVICE_PORT")
+
+flood_factor = 0 if (os.environ.get("FLOOD_FACTOR") is None) else int(os.environ.get("FLOOD_FACTOR"))
+
+details = {
+ "name": "http://{0}{1}:{2}".format(detailsHostname, servicesDomain, detailsPort),
+ "endpoint": "details",
+ "children": []
+}
+
+ratings = {
+ "name": "http://{0}{1}:{2}".format(ratingsHostname, servicesDomain, ratingsPort),
+ "endpoint": "ratings",
+ "children": []
+}
+
+reviews = {
+ "name": "http://{0}{1}:{2}".format(reviewsHostname, servicesDomain, reviewsPort),
+ "endpoint": "reviews",
+ "children": [ratings]
+}
+
+productpage = {
+ "name": "http://{0}{1}:{2}".format(detailsHostname, servicesDomain, detailsPort),
+ "endpoint": "details",
+ "children": [details, reviews]
+}
+
+service_dict = {
+ "productpage": productpage,
+ "details": details,
+ "reviews": reviews,
+}
+
+request_result_counter = Counter('request_result', 'Results of requests', ['destination_app', 'response_code'])
+
+# A note on distributed tracing:
+#
+# Although Istio proxies are able to automatically send spans, they need some
+# hints to tie together the entire trace. Applications need to propagate the
+# appropriate HTTP headers so that when the proxies send span information, the
+# spans can be correlated correctly into a single trace.
+#
+# To do this, an application needs to collect and propagate headers from the
+# incoming request to any outgoing requests. The choice of headers to propagate
+# is determined by the trace configuration used. See getForwardHeaders for
+# the different header options.
+#
+# This example code uses OpenTracing (http://opentracing.io/) to propagate
+# the 'b3' (zipkin) headers. Using OpenTracing for this is not a requirement.
+# Using OpenTracing allows you to add application-specific tracing later on,
+# but you can just manually forward the headers if you prefer.
+#
+# The OpenTracing example here is very basic. It only forwards headers. It is
+# intended as a reference to help people get started, eg how to create spans,
+# extract/inject context, etc.
+
+# A very basic OpenTracing tracer (with null reporter)
+tracer = Tracer(
+ one_span_per_rpc=True,
+ service_name='productpage',
+ reporter=NullReporter(),
+ sampler=ConstSampler(decision=True),
+ extra_codecs={Format.HTTP_HEADERS: B3Codec()}
+)
+
+
+def trace():
+ '''
+ Function decorator that creates opentracing span from incoming b3 headers
+ '''
+ def decorator(f):
+ def wrapper(*args, **kwargs):
+ request = stack.top.request
+ try:
+ # Create a new span context, reading in values (traceid,
+ # spanid, etc) from the incoming x-b3-*** headers.
+ span_ctx = tracer.extract(
+ Format.HTTP_HEADERS,
+ dict(request.headers)
+ )
+ # Note: this tag means that the span will *not* be
+ # a child span. It will use the incoming traceid and
+ # spanid. We do this to propagate the headers verbatim.
+ rpc_tag = {tags.SPAN_KIND: tags.SPAN_KIND_RPC_SERVER}
+ span = tracer.start_span(
+ operation_name='op', child_of=span_ctx, tags=rpc_tag
+ )
+ except Exception as e:
+ # We failed to create a context, possibly due to no
+ # incoming x-b3-*** headers. Start a fresh span.
+ # Note: This is a fallback only, and will create fresh headers,
+ # not propagate headers.
+ span = tracer.start_span('op')
+ with span_in_context(span):
+ r = f(*args, **kwargs)
+ return r
+ wrapper.__name__ = f.__name__
+ return wrapper
+ return decorator
+
+
+def getForwardHeaders(request):
+ headers = {}
+
+ # x-b3-*** headers can be populated using the opentracing span
+ span = get_current_span()
+ carrier = {}
+ tracer.inject(
+ span_context=span.context,
+ format=Format.HTTP_HEADERS,
+ carrier=carrier)
+
+ headers.update(carrier)
+
+ # We handle other (non x-b3-***) headers manually
+ if 'user' in session:
+ headers['end-user'] = session['user']
+
+ # Keep this in sync with the headers in details and reviews.
+ incoming_headers = [
+ # All applications should propagate x-request-id. This header is
+ # included in access log statements and is used for consistent trace
+ # sampling and log sampling decisions in Istio.
+ 'x-request-id',
+
+ # Lightstep tracing header. Propagate this if you use lightstep tracing
+ # in Istio (see
+ # https://istio.io/latest/docs/tasks/observability/distributed-tracing/lightstep/)
+ # Note: this should probably be changed to use B3 or W3C TRACE_CONTEXT.
+ # Lightstep recommends using B3 or TRACE_CONTEXT and most application
+ # libraries from lightstep do not support x-ot-span-context.
+ 'x-ot-span-context',
+
+ # Datadog tracing header. Propagate these headers if you use Datadog
+ # tracing.
+ 'x-datadog-trace-id',
+ 'x-datadog-parent-id',
+ 'x-datadog-sampling-priority',
+
+ # W3C Trace Context. Compatible with OpenCensusAgent and Stackdriver Istio
+ # configurations.
+ 'traceparent',
+ 'tracestate',
+
+ # Cloud trace context. Compatible with OpenCensusAgent and Stackdriver Istio
+ # configurations.
+ 'x-cloud-trace-context',
+
+ # Grpc binary trace context. Compatible with OpenCensusAgent nad
+ # Stackdriver Istio configurations.
+ 'grpc-trace-bin',
+
+ # b3 trace headers. Compatible with Zipkin, OpenCensusAgent, and
+ # Stackdriver Istio configurations. Commented out since they are
+ # propagated by the OpenTracing tracer above.
+ # 'x-b3-traceid',
+ # 'x-b3-spanid',
+ # 'x-b3-parentspanid',
+ # 'x-b3-sampled',
+ # 'x-b3-flags',
+
+ # SkyWalking trace headers.
+ 'sw8',
+
+ # Application-specific headers to forward.
+ 'user-agent',
+
+ # Context and session specific headers
+ 'cookie',
+ 'authorization',
+ 'jwt',
+ ]
+ # For Zipkin, always propagate b3 headers.
+ # For Lightstep, always propagate the x-ot-span-context header.
+ # For Datadog, propagate the corresponding datadog headers.
+ # For OpenCensusAgent and Stackdriver configurations, you can choose any
+ # set of compatible headers to propagate within your application. For
+ # example, you can propagate b3 headers or W3C trace context headers with
+ # the same result. This can also allow you to translate between context
+ # propagation mechanisms between different applications.
+
+ for ihdr in incoming_headers:
+ val = request.headers.get(ihdr)
+ if val is not None:
+ headers[ihdr] = val
+
+ return headers
+
+
+# The UI:
+@app.route('/')
+@app.route('/index.html')
+def index():
+ """ Display productpage with normal user and test user buttons"""
+ global productpage
+
+ table = json2html.convert(json=json.dumps(productpage),
+ table_attributes="class=\"table table-condensed table-bordered table-hover\"")
+
+ return render_template('index.html', serviceTable=table)
+
+
+@app.route('/health')
+def health():
+ return 'Product page is healthy'
+
+
+@app.route('/login', methods=['POST'])
+def login():
+ user = request.values.get('username')
+ response = app.make_response(redirect(request.referrer))
+ session['user'] = user
+ return response
+
+
+@app.route('/logout', methods=['GET'])
+def logout():
+ response = app.make_response(redirect(request.referrer))
+ session.pop('user', None)
+ return response
+
+# a helper function for asyncio.gather, does not return a value
+
+
+async def getProductReviewsIgnoreResponse(product_id, headers):
+ getProductReviews(product_id, headers)
+
+# flood reviews with unnecessary requests to demonstrate Istio rate limiting, asynchoronously
+
+
+async def floodReviewsAsynchronously(product_id, headers):
+ # the response is disregarded
+ await asyncio.gather(*(getProductReviewsIgnoreResponse(product_id, headers) for _ in range(flood_factor)))
+
+# flood reviews with unnecessary requests to demonstrate Istio rate limiting
+
+
+def floodReviews(product_id, headers):
+ loop = asyncio.new_event_loop()
+ loop.run_until_complete(floodReviewsAsynchronously(product_id, headers))
+ loop.close()
+
+
+@app.route('/productpage')
+@trace()
+def front():
+ product_id = 0 # TODO: replace default value
+ headers = getForwardHeaders(request)
+ user = session.get('user', '')
+ product = getProduct(product_id)
+ detailsStatus, details = getProductDetails(product_id, headers)
+
+ if flood_factor > 0:
+ floodReviews(product_id, headers)
+
+ reviewsStatus, reviews = getProductReviews(product_id, headers)
+ return render_template(
+ 'productpage.html',
+ detailsStatus=detailsStatus,
+ reviewsStatus=reviewsStatus,
+ product=product,
+ details=details,
+ reviews=reviews,
+ user=user)
+
+
+# The API:
+@app.route('/api/v1/products')
+def productsRoute():
+ return json.dumps(getProducts()), 200, {'Content-Type': 'application/json'}
+
+
+@app.route('/api/v1/products/')
+@trace()
+def productRoute(product_id):
+ headers = getForwardHeaders(request)
+ status, details = getProductDetails(product_id, headers)
+ return json.dumps(details), status, {'Content-Type': 'application/json'}
+
+
+@app.route('/api/v1/products//reviews')
+@trace()
+def reviewsRoute(product_id):
+ headers = getForwardHeaders(request)
+ status, reviews = getProductReviews(product_id, headers)
+ return json.dumps(reviews), status, {'Content-Type': 'application/json'}
+
+
+@app.route('/api/v1/products//ratings')
+@trace()
+def ratingsRoute(product_id):
+ headers = getForwardHeaders(request)
+ status, ratings = getProductRatings(product_id, headers)
+ return json.dumps(ratings), status, {'Content-Type': 'application/json'}
+
+
+@app.route('/metrics')
+def metrics():
+ return generate_latest()
+
+
+# Data providers:
+def getProducts():
+ return [
+ {
+ 'id': 0,
+ 'title': 'The Comedy of Errors',
+ 'descriptionHtml': 'Wikipedia Summary : The Comedy of Errors is one of William Shakespeare\'s early plays. It is his shortest and one of his most farcical comedies, with a major part of the humour coming from slapstick and mistaken identity, in addition to puns and word play.'
+ }
+ ]
+
+
+def getProduct(product_id):
+ products = getProducts()
+ if product_id + 1 > len(products):
+ return None
+ else:
+ return products[product_id]
+
+
+def getProductDetails(product_id, headers):
+ try:
+ url = details['name'] + "/" + details['endpoint'] + "/" + str(product_id)
+ res = requests.get(url, headers=headers, timeout=3.0)
+ except BaseException:
+ res = None
+ if res and res.status_code == 200:
+ request_result_counter.labels(destination_app='details', response_code=200).inc()
+ return 200, res.json()
+ else:
+ status = res.status_code if res is not None and res.status_code else 500
+ request_result_counter.labels(destination_app='details', response_code=status).inc()
+ return status, {'error': 'Sorry, product details are currently unavailable for this book.'}
+
+
+def getProductReviews(product_id, headers):
+ # Do not remove. Bug introduced explicitly for illustration in fault injection task
+ # TODO: Figure out how to achieve the same effect using Envoy retries/timeouts
+ for _ in range(2):
+ try:
+ url = reviews['name'] + "/" + reviews['endpoint'] + "/" + str(product_id)
+ res = requests.get(url, headers=headers, timeout=3.0)
+ except BaseException:
+ res = None
+ if res and res.status_code == 200:
+ request_result_counter.labels(destination_app='reviews', response_code=200).inc()
+ return 200, res.json()
+ status = res.status_code if res is not None and res.status_code else 500
+ request_result_counter.labels(destination_app='reviews', response_code=status).inc()
+ return status, {'error': 'Sorry, product reviews are currently unavailable for this book.'}
+
+
+def getProductRatings(product_id, headers):
+ try:
+ url = ratings['name'] + "/" + ratings['endpoint'] + "/" + str(product_id)
+ res = requests.get(url, headers=headers, timeout=3.0)
+ except BaseException:
+ res = None
+ if res and res.status_code == 200:
+ request_result_counter.labels(destination_app='ratings', response_code=200).inc()
+ return 200, res.json()
+ else:
+ status = res.status_code if res is not None and res.status_code else 500
+ request_result_counter.labels(destination_app='ratings', response_code=status).inc()
+ return status, {'error': 'Sorry, product ratings are currently unavailable for this book.'}
+
+
+class Writer(object):
+ def __init__(self, filename):
+ self.file = open(filename, 'w')
+
+ def write(self, data):
+ self.file.write(data)
+
+ def flush(self):
+ self.file.flush()
+
+
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ logging.error("usage: %s port" % (sys.argv[0]))
+ sys.exit(-1)
+
+ p = int(sys.argv[1])
+ logging.info("start at port %s" % (p))
+ # Make it compatible with IPv6 if Linux
+ if sys.platform == "linux":
+ app.run(host='::', port=p, debug=True, threaded=True)
+ else:
+ app.run(host='0.0.0.0', port=p, debug=True, threaded=True)
diff --git a/Istio-Samples/bookinfo/src/productpage/requirements.txt b/Istio-Samples/bookinfo/src/productpage/requirements.txt
new file mode 100644
index 00000000..2fa17157
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/requirements.txt
@@ -0,0 +1,11 @@
+Flask==2.2.5
+Flask-Bootstrap==3.3.7.1
+Flask-JSON==0.4.0
+future==0.18.3
+jaeger-client==3.13.0
+json2html==1.3.0
+opentracing==1.2.2
+opentracing-instrumentation==2.4.3
+prometheus-client==0.17.0
+simplejson==3.19.1
+urllib3==2.0.7
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap-theme.css b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap-theme.css
new file mode 100644
index 00000000..c19cd5c4
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap-theme.css
@@ -0,0 +1,587 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+.btn-default,
+.btn-primary,
+.btn-success,
+.btn-info,
+.btn-warning,
+.btn-danger {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+}
+.btn-default:active,
+.btn-primary:active,
+.btn-success:active,
+.btn-info:active,
+.btn-warning:active,
+.btn-danger:active,
+.btn-default.active,
+.btn-primary.active,
+.btn-success.active,
+.btn-info.active,
+.btn-warning.active,
+.btn-danger.active {
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-default.disabled,
+.btn-primary.disabled,
+.btn-success.disabled,
+.btn-info.disabled,
+.btn-warning.disabled,
+.btn-danger.disabled,
+.btn-default[disabled],
+.btn-primary[disabled],
+.btn-success[disabled],
+.btn-info[disabled],
+.btn-warning[disabled],
+.btn-danger[disabled],
+fieldset[disabled] .btn-default,
+fieldset[disabled] .btn-primary,
+fieldset[disabled] .btn-success,
+fieldset[disabled] .btn-info,
+fieldset[disabled] .btn-warning,
+fieldset[disabled] .btn-danger {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.btn-default .badge,
+.btn-primary .badge,
+.btn-success .badge,
+.btn-info .badge,
+.btn-warning .badge,
+.btn-danger .badge {
+ text-shadow: none;
+}
+.btn:active,
+.btn.active {
+ background-image: none;
+}
+.btn-default {
+ text-shadow: 0 1px 0 #fff;
+ background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+ background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
+ background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #dbdbdb;
+ border-color: #ccc;
+}
+.btn-default:hover,
+.btn-default:focus {
+ background-color: #e0e0e0;
+ background-position: 0 -15px;
+}
+.btn-default:active,
+.btn-default.active {
+ background-color: #e0e0e0;
+ border-color: #dbdbdb;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+fieldset[disabled] .btn-default,
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus,
+.btn-default.disabled:active,
+.btn-default[disabled]:active,
+fieldset[disabled] .btn-default:active,
+.btn-default.disabled.active,
+.btn-default[disabled].active,
+fieldset[disabled] .btn-default.active {
+ background-color: #e0e0e0;
+ background-image: none;
+}
+.btn-primary {
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #245580;
+}
+.btn-primary:hover,
+.btn-primary:focus {
+ background-color: #265a88;
+ background-position: 0 -15px;
+}
+.btn-primary:active,
+.btn-primary.active {
+ background-color: #265a88;
+ border-color: #245580;
+}
+.btn-primary.disabled,
+.btn-primary[disabled],
+fieldset[disabled] .btn-primary,
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus,
+.btn-primary.disabled:active,
+.btn-primary[disabled]:active,
+fieldset[disabled] .btn-primary:active,
+.btn-primary.disabled.active,
+.btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active {
+ background-color: #265a88;
+ background-image: none;
+}
+.btn-success {
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
+ background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #3e8f3e;
+}
+.btn-success:hover,
+.btn-success:focus {
+ background-color: #419641;
+ background-position: 0 -15px;
+}
+.btn-success:active,
+.btn-success.active {
+ background-color: #419641;
+ border-color: #3e8f3e;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+fieldset[disabled] .btn-success,
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus,
+.btn-success.disabled:active,
+.btn-success[disabled]:active,
+fieldset[disabled] .btn-success:active,
+.btn-success.disabled.active,
+.btn-success[disabled].active,
+fieldset[disabled] .btn-success.active {
+ background-color: #419641;
+ background-image: none;
+}
+.btn-info {
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+ background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #28a4c9;
+}
+.btn-info:hover,
+.btn-info:focus {
+ background-color: #2aabd2;
+ background-position: 0 -15px;
+}
+.btn-info:active,
+.btn-info.active {
+ background-color: #2aabd2;
+ border-color: #28a4c9;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+fieldset[disabled] .btn-info,
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus,
+.btn-info.disabled:active,
+.btn-info[disabled]:active,
+fieldset[disabled] .btn-info:active,
+.btn-info.disabled.active,
+.btn-info[disabled].active,
+fieldset[disabled] .btn-info.active {
+ background-color: #2aabd2;
+ background-image: none;
+}
+.btn-warning {
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+ background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #e38d13;
+}
+.btn-warning:hover,
+.btn-warning:focus {
+ background-color: #eb9316;
+ background-position: 0 -15px;
+}
+.btn-warning:active,
+.btn-warning.active {
+ background-color: #eb9316;
+ border-color: #e38d13;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+fieldset[disabled] .btn-warning,
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus,
+.btn-warning.disabled:active,
+.btn-warning[disabled]:active,
+fieldset[disabled] .btn-warning:active,
+.btn-warning.disabled.active,
+.btn-warning[disabled].active,
+fieldset[disabled] .btn-warning.active {
+ background-color: #eb9316;
+ background-image: none;
+}
+.btn-danger {
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+ background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #b92c28;
+}
+.btn-danger:hover,
+.btn-danger:focus {
+ background-color: #c12e2a;
+ background-position: 0 -15px;
+}
+.btn-danger:active,
+.btn-danger.active {
+ background-color: #c12e2a;
+ border-color: #b92c28;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+fieldset[disabled] .btn-danger,
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus,
+.btn-danger.disabled:active,
+.btn-danger[disabled]:active,
+fieldset[disabled] .btn-danger:active,
+.btn-danger.disabled.active,
+.btn-danger[disabled].active,
+fieldset[disabled] .btn-danger.active {
+ background-color: #c12e2a;
+ background-image: none;
+}
+.thumbnail,
+.img-thumbnail {
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ background-color: #e8e8e8;
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+ background-repeat: repeat-x;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ background-color: #2e6da4;
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+ background-repeat: repeat-x;
+}
+.navbar-default {
+ background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+ background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
+ background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .active > a {
+ background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+ background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
+ background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
+ background-repeat: repeat-x;
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+}
+.navbar-brand,
+.navbar-nav > li > a {
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
+}
+.navbar-inverse {
+ background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
+ background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
+ background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-radius: 4px;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .active > a {
+ background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
+ background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
+ background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
+ background-repeat: repeat-x;
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+}
+.navbar-inverse .navbar-brand,
+.navbar-inverse .navbar-nav > li > a {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
+}
+.navbar-static-top,
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ border-radius: 0;
+}
+@media (max-width: 767px) {
+ .navbar .navbar-nav .open .dropdown-menu > .active > a,
+ .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
+ .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
+ color: #fff;
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+ background-repeat: repeat-x;
+ }
+}
+.alert {
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+}
+.alert-success {
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+ background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #b2dba1;
+}
+.alert-info {
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+ background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #9acfea;
+}
+.alert-warning {
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+ background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #f5e79e;
+}
+.alert-danger {
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+ background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
+ background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #dca7a7;
+}
+.progress {
+ background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+ background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar {
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-success {
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+ background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-info {
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+ background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-warning {
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+ background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-danger {
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+ background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-striped {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.list-group {
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+ text-shadow: 0 -1px 0 #286090;
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #2b669a;
+}
+.list-group-item.active .badge,
+.list-group-item.active:hover .badge,
+.list-group-item.active:focus .badge {
+ text-shadow: none;
+}
+.panel {
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+}
+.panel-default > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-primary > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-success > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+ background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-info > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+ background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-warning > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+ background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-danger > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+ background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
+ background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
+ background-repeat: repeat-x;
+}
+.well {
+ background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+ background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
+ background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #dcdcdc;
+ -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+}
+/*# sourceMappingURL=bootstrap-theme.css.map */
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap-theme.css.map b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap-theme.css.map
new file mode 100644
index 00000000..75353114
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap-theme.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["bootstrap-theme.css","less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAAA;;;;GAIG;ACeH;;;;;;EAME,yCAAA;EC2CA,4FAAA;EACQ,oFAAA;CFvDT;ACgBC;;;;;;;;;;;;ECsCA,yDAAA;EACQ,iDAAA;CFxCT;ACMC;;;;;;;;;;;;;;;;;;ECiCA,yBAAA;EACQ,iBAAA;CFnBT;AC/BD;;;;;;EAuBI,kBAAA;CDgBH;ACyBC;;EAEE,uBAAA;CDvBH;AC4BD;EErEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;EAuC2C,0BAAA;EAA2B,mBAAA;CDjBvE;ACpBC;;EAEE,0BAAA;EACA,6BAAA;CDsBH;ACnBC;;EAEE,0BAAA;EACA,sBAAA;CDqBH;ACfG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CD6BL;ACbD;EEtEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CD8DD;AC5DC;;EAEE,0BAAA;EACA,6BAAA;CD8DH;AC3DC;;EAEE,0BAAA;EACA,sBAAA;CD6DH;ACvDG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CDqEL;ACpDD;EEvEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CDsGD;ACpGC;;EAEE,0BAAA;EACA,6BAAA;CDsGH;ACnGC;;EAEE,0BAAA;EACA,sBAAA;CDqGH;AC/FG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CD6GL;AC3FD;EExEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CD8ID;AC5IC;;EAEE,0BAAA;EACA,6BAAA;CD8IH;AC3IC;;EAEE,0BAAA;EACA,sBAAA;CD6IH;ACvIG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CDqJL;AClID;EEzEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CDsLD;ACpLC;;EAEE,0BAAA;EACA,6BAAA;CDsLH;ACnLC;;EAEE,0BAAA;EACA,sBAAA;CDqLH;AC/KG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CD6LL;ACzKD;EE1EI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CD8ND;AC5NC;;EAEE,0BAAA;EACA,6BAAA;CD8NH;AC3NC;;EAEE,0BAAA;EACA,sBAAA;CD6NH;ACvNG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CDqOL;AC1MD;;EClCE,mDAAA;EACQ,2CAAA;CFgPT;ACrMD;;EE3FI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF0FF,0BAAA;CD2MD;ACzMD;;;EEhGI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EFgGF,0BAAA;CD+MD;ACtMD;EE7GI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ECnBF,oEAAA;EH+HA,mBAAA;ECjEA,4FAAA;EACQ,oFAAA;CF8QT;ACjND;;EE7GI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ED2CF,yDAAA;EACQ,iDAAA;CFwRT;AC9MD;;EAEE,+CAAA;CDgND;AC5MD;EEhII,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ECnBF,oEAAA;EHkJA,mBAAA;CDkND;ACrND;;EEhII,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ED2CF,wDAAA;EACQ,gDAAA;CF+ST;AC/ND;;EAYI,0CAAA;CDuNH;AClND;;;EAGE,iBAAA;CDoND;AC/LD;EAfI;;;IAGE,YAAA;IE7JF,yEAAA;IACA,oEAAA;IACA,8FAAA;IAAA,uEAAA;IACA,4BAAA;IACA,uHAAA;GH+WD;CACF;AC3MD;EACE,8CAAA;EC3HA,2FAAA;EACQ,mFAAA;CFyUT;ACnMD;EEtLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CD+MD;AC1MD;EEvLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CDuND;ACjND;EExLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CD+ND;ACxND;EEzLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CDuOD;ACxND;EEjMI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH4ZH;ACrND;EE3MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHmaH;AC3ND;EE5MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH0aH;ACjOD;EE7MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHibH;ACvOD;EE9MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHwbH;AC7OD;EE/MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH+bH;AChPD;EElLI,8MAAA;EACA,yMAAA;EACA,sMAAA;CHqaH;AC5OD;EACE,mBAAA;EC9KA,mDAAA;EACQ,2CAAA;CF6ZT;AC7OD;;;EAGE,8BAAA;EEnOE,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EFiOF,sBAAA;CDmPD;ACxPD;;;EAQI,kBAAA;CDqPH;AC3OD;ECnME,kDAAA;EACQ,0CAAA;CFibT;ACrOD;EE5PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHoeH;AC3OD;EE7PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH2eH;ACjPD;EE9PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHkfH;ACvPD;EE/PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHyfH;AC7PD;EEhQI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHggBH;ACnQD;EEjQI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHugBH;ACnQD;EExQI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EFsQF,sBAAA;EC3NA,0FAAA;EACQ,kFAAA;CFqeT","file":"bootstrap-theme.css","sourcesContent":["/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-default.disabled,\n.btn-primary.disabled,\n.btn-success.disabled,\n.btn-info.disabled,\n.btn-warning.disabled,\n.btn-danger.disabled,\n.btn-default[disabled],\n.btn-primary[disabled],\n.btn-success[disabled],\n.btn-info[disabled],\n.btn-warning[disabled],\n.btn-danger[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-danger {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n text-shadow: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n}\n.btn-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #dbdbdb;\n text-shadow: 0 1px 0 #fff;\n border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n background-color: #e0e0e0;\n background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n background-color: #e0e0e0;\n border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n background-color: #e0e0e0;\n background-image: none;\n}\n.btn-primary {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #245580;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n background-color: #265a88;\n background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n background-color: #265a88;\n border-color: #245580;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n background-color: #265a88;\n background-image: none;\n}\n.btn-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n background-color: #419641;\n background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n background-color: #419641;\n border-color: #3e8f3e;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n background-color: #419641;\n background-image: none;\n}\n.btn-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n background-color: #2aabd2;\n background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n background-color: #2aabd2;\n border-color: #28a4c9;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n background-color: #2aabd2;\n background-image: none;\n}\n.btn-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n background-color: #eb9316;\n background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n background-color: #eb9316;\n border-color: #e38d13;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n background-color: #eb9316;\n background-image: none;\n}\n.btn-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n background-color: #c12e2a;\n background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n background-color: #c12e2a;\n border-color: #b92c28;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n background-color: #c12e2a;\n background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n background-color: #e8e8e8;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-color: #2e6da4;\n}\n.navbar-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n.navbar-inverse {\n background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%);\n background-image: -o-linear-gradient(top, #3c3c3c 0%, #222222 100%);\n background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n@media (max-width: 767px) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n }\n}\n.alert {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.alert-success {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n border-color: #b2dba1;\n}\n.alert-info {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n border-color: #9acfea;\n}\n.alert-warning {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n border-color: #f5e79e;\n}\n.alert-danger {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n border-color: #dca7a7;\n}\n.progress {\n background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n}\n.progress-bar {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);\n}\n.progress-bar-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n}\n.progress-bar-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n}\n.progress-bar-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n}\n.progress-bar-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n}\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.list-group {\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 #286090;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);\n border-color: #2b669a;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n text-shadow: none;\n}\n.panel {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.panel-default > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n}\n.panel-primary > .panel-heading {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n}\n.panel-success > .panel-heading {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n}\n.panel-info > .panel-heading {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n}\n.panel-warning > .panel-heading {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n}\n.panel-danger > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n}\n.well {\n background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n border-color: #dcdcdc;\n -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */","/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n .box-shadow(none);\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n border-radius: @navbar-border-radius;\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]}
\ No newline at end of file
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap-theme.min.css b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap-theme.min.css
new file mode 100644
index 00000000..61358b13
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap-theme.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}
\ No newline at end of file
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap.css b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap.css
new file mode 100644
index 00000000..680e7687
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap.css
@@ -0,0 +1,6800 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+html {
+ font-family: sans-serif;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+}
+body {
+ margin: 0;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+ display: block;
+}
+audio,
+canvas,
+progress,
+video {
+ display: inline-block;
+ vertical-align: baseline;
+}
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+[hidden],
+template {
+ display: none;
+}
+a {
+ background-color: transparent;
+}
+a:active,
+a:hover {
+ outline: 0;
+}
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+b,
+strong {
+ font-weight: bold;
+}
+dfn {
+ font-style: italic;
+}
+h1 {
+ margin: .67em 0;
+ font-size: 2em;
+}
+mark {
+ color: #000;
+ background: #ff0;
+}
+small {
+ font-size: 80%;
+}
+sub,
+sup {
+ position: relative;
+ font-size: 75%;
+ line-height: 0;
+ vertical-align: baseline;
+}
+sup {
+ top: -.5em;
+}
+sub {
+ bottom: -.25em;
+}
+img {
+ border: 0;
+}
+svg:not(:root) {
+ overflow: hidden;
+}
+figure {
+ margin: 1em 40px;
+}
+hr {
+ height: 0;
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+pre {
+ overflow: auto;
+}
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, monospace;
+ font-size: 1em;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+ margin: 0;
+ font: inherit;
+ color: inherit;
+}
+button {
+ overflow: visible;
+}
+button,
+select {
+ text-transform: none;
+}
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button;
+ cursor: pointer;
+}
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+input {
+ line-height: normal;
+}
+input[type="checkbox"],
+input[type="radio"] {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 0;
+}
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+input[type="search"] {
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ -webkit-appearance: textfield;
+}
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+fieldset {
+ padding: .35em .625em .75em;
+ margin: 0 2px;
+ border: 1px solid #c0c0c0;
+}
+legend {
+ padding: 0;
+ border: 0;
+}
+textarea {
+ overflow: auto;
+}
+optgroup {
+ font-weight: bold;
+}
+table {
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+td,
+th {
+ padding: 0;
+}
+/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
+@media print {
+ *,
+ *:before,
+ *:after {
+ color: #000 !important;
+ text-shadow: none !important;
+ background: transparent !important;
+ -webkit-box-shadow: none !important;
+ box-shadow: none !important;
+ }
+ a,
+ a:visited {
+ text-decoration: underline;
+ }
+ a[href]:after {
+ content: " (" attr(href) ")";
+ }
+ abbr[title]:after {
+ content: " (" attr(title) ")";
+ }
+ a[href^="#"]:after,
+ a[href^="javascript:"]:after {
+ content: "";
+ }
+ pre,
+ blockquote {
+ border: 1px solid #999;
+
+ page-break-inside: avoid;
+ }
+ thead {
+ display: table-header-group;
+ }
+ tr,
+ img {
+ page-break-inside: avoid;
+ }
+ img {
+ max-width: 100% !important;
+ }
+ p,
+ h2,
+ h3 {
+ orphans: 3;
+ widows: 3;
+ }
+ h2,
+ h3 {
+ page-break-after: avoid;
+ }
+ .navbar {
+ display: none;
+ }
+ .btn > .caret,
+ .dropup > .btn > .caret {
+ border-top-color: #000 !important;
+ }
+ .label {
+ border: 1px solid #000;
+ }
+ .table {
+ border-collapse: collapse !important;
+ }
+ .table td,
+ .table th {
+ background-color: #fff !important;
+ }
+ .table-bordered th,
+ .table-bordered td {
+ border: 1px solid #ddd !important;
+ }
+}
+@font-face {
+ font-family: 'Glyphicons Halflings';
+
+ src: url('../fonts/glyphicons-halflings-regular.eot');
+ src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
+}
+.glyphicon {
+ position: relative;
+ top: 1px;
+ display: inline-block;
+ font-family: 'Glyphicons Halflings';
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+.glyphicon-asterisk:before {
+ content: "\2a";
+}
+.glyphicon-plus:before {
+ content: "\2b";
+}
+.glyphicon-euro:before,
+.glyphicon-eur:before {
+ content: "\20ac";
+}
+.glyphicon-minus:before {
+ content: "\2212";
+}
+.glyphicon-cloud:before {
+ content: "\2601";
+}
+.glyphicon-envelope:before {
+ content: "\2709";
+}
+.glyphicon-pencil:before {
+ content: "\270f";
+}
+.glyphicon-glass:before {
+ content: "\e001";
+}
+.glyphicon-music:before {
+ content: "\e002";
+}
+.glyphicon-search:before {
+ content: "\e003";
+}
+.glyphicon-heart:before {
+ content: "\e005";
+}
+.glyphicon-star:before {
+ content: "\e006";
+}
+.glyphicon-star-empty:before {
+ content: "\e007";
+}
+.glyphicon-user:before {
+ content: "\e008";
+}
+.glyphicon-film:before {
+ content: "\e009";
+}
+.glyphicon-th-large:before {
+ content: "\e010";
+}
+.glyphicon-th:before {
+ content: "\e011";
+}
+.glyphicon-th-list:before {
+ content: "\e012";
+}
+.glyphicon-ok:before {
+ content: "\e013";
+}
+.glyphicon-remove:before {
+ content: "\e014";
+}
+.glyphicon-zoom-in:before {
+ content: "\e015";
+}
+.glyphicon-zoom-out:before {
+ content: "\e016";
+}
+.glyphicon-off:before {
+ content: "\e017";
+}
+.glyphicon-signal:before {
+ content: "\e018";
+}
+.glyphicon-cog:before {
+ content: "\e019";
+}
+.glyphicon-trash:before {
+ content: "\e020";
+}
+.glyphicon-home:before {
+ content: "\e021";
+}
+.glyphicon-file:before {
+ content: "\e022";
+}
+.glyphicon-time:before {
+ content: "\e023";
+}
+.glyphicon-road:before {
+ content: "\e024";
+}
+.glyphicon-download-alt:before {
+ content: "\e025";
+}
+.glyphicon-download:before {
+ content: "\e026";
+}
+.glyphicon-upload:before {
+ content: "\e027";
+}
+.glyphicon-inbox:before {
+ content: "\e028";
+}
+.glyphicon-play-circle:before {
+ content: "\e029";
+}
+.glyphicon-repeat:before {
+ content: "\e030";
+}
+.glyphicon-refresh:before {
+ content: "\e031";
+}
+.glyphicon-list-alt:before {
+ content: "\e032";
+}
+.glyphicon-lock:before {
+ content: "\e033";
+}
+.glyphicon-flag:before {
+ content: "\e034";
+}
+.glyphicon-headphones:before {
+ content: "\e035";
+}
+.glyphicon-volume-off:before {
+ content: "\e036";
+}
+.glyphicon-volume-down:before {
+ content: "\e037";
+}
+.glyphicon-volume-up:before {
+ content: "\e038";
+}
+.glyphicon-qrcode:before {
+ content: "\e039";
+}
+.glyphicon-barcode:before {
+ content: "\e040";
+}
+.glyphicon-tag:before {
+ content: "\e041";
+}
+.glyphicon-tags:before {
+ content: "\e042";
+}
+.glyphicon-book:before {
+ content: "\e043";
+}
+.glyphicon-bookmark:before {
+ content: "\e044";
+}
+.glyphicon-print:before {
+ content: "\e045";
+}
+.glyphicon-camera:before {
+ content: "\e046";
+}
+.glyphicon-font:before {
+ content: "\e047";
+}
+.glyphicon-bold:before {
+ content: "\e048";
+}
+.glyphicon-italic:before {
+ content: "\e049";
+}
+.glyphicon-text-height:before {
+ content: "\e050";
+}
+.glyphicon-text-width:before {
+ content: "\e051";
+}
+.glyphicon-align-left:before {
+ content: "\e052";
+}
+.glyphicon-align-center:before {
+ content: "\e053";
+}
+.glyphicon-align-right:before {
+ content: "\e054";
+}
+.glyphicon-align-justify:before {
+ content: "\e055";
+}
+.glyphicon-list:before {
+ content: "\e056";
+}
+.glyphicon-indent-left:before {
+ content: "\e057";
+}
+.glyphicon-indent-right:before {
+ content: "\e058";
+}
+.glyphicon-facetime-video:before {
+ content: "\e059";
+}
+.glyphicon-picture:before {
+ content: "\e060";
+}
+.glyphicon-map-marker:before {
+ content: "\e062";
+}
+.glyphicon-adjust:before {
+ content: "\e063";
+}
+.glyphicon-tint:before {
+ content: "\e064";
+}
+.glyphicon-edit:before {
+ content: "\e065";
+}
+.glyphicon-share:before {
+ content: "\e066";
+}
+.glyphicon-check:before {
+ content: "\e067";
+}
+.glyphicon-move:before {
+ content: "\e068";
+}
+.glyphicon-step-backward:before {
+ content: "\e069";
+}
+.glyphicon-fast-backward:before {
+ content: "\e070";
+}
+.glyphicon-backward:before {
+ content: "\e071";
+}
+.glyphicon-play:before {
+ content: "\e072";
+}
+.glyphicon-pause:before {
+ content: "\e073";
+}
+.glyphicon-stop:before {
+ content: "\e074";
+}
+.glyphicon-forward:before {
+ content: "\e075";
+}
+.glyphicon-fast-forward:before {
+ content: "\e076";
+}
+.glyphicon-step-forward:before {
+ content: "\e077";
+}
+.glyphicon-eject:before {
+ content: "\e078";
+}
+.glyphicon-chevron-left:before {
+ content: "\e079";
+}
+.glyphicon-chevron-right:before {
+ content: "\e080";
+}
+.glyphicon-plus-sign:before {
+ content: "\e081";
+}
+.glyphicon-minus-sign:before {
+ content: "\e082";
+}
+.glyphicon-remove-sign:before {
+ content: "\e083";
+}
+.glyphicon-ok-sign:before {
+ content: "\e084";
+}
+.glyphicon-question-sign:before {
+ content: "\e085";
+}
+.glyphicon-info-sign:before {
+ content: "\e086";
+}
+.glyphicon-screenshot:before {
+ content: "\e087";
+}
+.glyphicon-remove-circle:before {
+ content: "\e088";
+}
+.glyphicon-ok-circle:before {
+ content: "\e089";
+}
+.glyphicon-ban-circle:before {
+ content: "\e090";
+}
+.glyphicon-arrow-left:before {
+ content: "\e091";
+}
+.glyphicon-arrow-right:before {
+ content: "\e092";
+}
+.glyphicon-arrow-up:before {
+ content: "\e093";
+}
+.glyphicon-arrow-down:before {
+ content: "\e094";
+}
+.glyphicon-share-alt:before {
+ content: "\e095";
+}
+.glyphicon-resize-full:before {
+ content: "\e096";
+}
+.glyphicon-resize-small:before {
+ content: "\e097";
+}
+.glyphicon-exclamation-sign:before {
+ content: "\e101";
+}
+.glyphicon-gift:before {
+ content: "\e102";
+}
+.glyphicon-leaf:before {
+ content: "\e103";
+}
+.glyphicon-fire:before {
+ content: "\e104";
+}
+.glyphicon-eye-open:before {
+ content: "\e105";
+}
+.glyphicon-eye-close:before {
+ content: "\e106";
+}
+.glyphicon-warning-sign:before {
+ content: "\e107";
+}
+.glyphicon-plane:before {
+ content: "\e108";
+}
+.glyphicon-calendar:before {
+ content: "\e109";
+}
+.glyphicon-random:before {
+ content: "\e110";
+}
+.glyphicon-comment:before {
+ content: "\e111";
+}
+.glyphicon-magnet:before {
+ content: "\e112";
+}
+.glyphicon-chevron-up:before {
+ content: "\e113";
+}
+.glyphicon-chevron-down:before {
+ content: "\e114";
+}
+.glyphicon-retweet:before {
+ content: "\e115";
+}
+.glyphicon-shopping-cart:before {
+ content: "\e116";
+}
+.glyphicon-folder-close:before {
+ content: "\e117";
+}
+.glyphicon-folder-open:before {
+ content: "\e118";
+}
+.glyphicon-resize-vertical:before {
+ content: "\e119";
+}
+.glyphicon-resize-horizontal:before {
+ content: "\e120";
+}
+.glyphicon-hdd:before {
+ content: "\e121";
+}
+.glyphicon-bullhorn:before {
+ content: "\e122";
+}
+.glyphicon-bell:before {
+ content: "\e123";
+}
+.glyphicon-certificate:before {
+ content: "\e124";
+}
+.glyphicon-thumbs-up:before {
+ content: "\e125";
+}
+.glyphicon-thumbs-down:before {
+ content: "\e126";
+}
+.glyphicon-hand-right:before {
+ content: "\e127";
+}
+.glyphicon-hand-left:before {
+ content: "\e128";
+}
+.glyphicon-hand-up:before {
+ content: "\e129";
+}
+.glyphicon-hand-down:before {
+ content: "\e130";
+}
+.glyphicon-circle-arrow-right:before {
+ content: "\e131";
+}
+.glyphicon-circle-arrow-left:before {
+ content: "\e132";
+}
+.glyphicon-circle-arrow-up:before {
+ content: "\e133";
+}
+.glyphicon-circle-arrow-down:before {
+ content: "\e134";
+}
+.glyphicon-globe:before {
+ content: "\e135";
+}
+.glyphicon-wrench:before {
+ content: "\e136";
+}
+.glyphicon-tasks:before {
+ content: "\e137";
+}
+.glyphicon-filter:before {
+ content: "\e138";
+}
+.glyphicon-briefcase:before {
+ content: "\e139";
+}
+.glyphicon-fullscreen:before {
+ content: "\e140";
+}
+.glyphicon-dashboard:before {
+ content: "\e141";
+}
+.glyphicon-paperclip:before {
+ content: "\e142";
+}
+.glyphicon-heart-empty:before {
+ content: "\e143";
+}
+.glyphicon-link:before {
+ content: "\e144";
+}
+.glyphicon-phone:before {
+ content: "\e145";
+}
+.glyphicon-pushpin:before {
+ content: "\e146";
+}
+.glyphicon-usd:before {
+ content: "\e148";
+}
+.glyphicon-gbp:before {
+ content: "\e149";
+}
+.glyphicon-sort:before {
+ content: "\e150";
+}
+.glyphicon-sort-by-alphabet:before {
+ content: "\e151";
+}
+.glyphicon-sort-by-alphabet-alt:before {
+ content: "\e152";
+}
+.glyphicon-sort-by-order:before {
+ content: "\e153";
+}
+.glyphicon-sort-by-order-alt:before {
+ content: "\e154";
+}
+.glyphicon-sort-by-attributes:before {
+ content: "\e155";
+}
+.glyphicon-sort-by-attributes-alt:before {
+ content: "\e156";
+}
+.glyphicon-unchecked:before {
+ content: "\e157";
+}
+.glyphicon-expand:before {
+ content: "\e158";
+}
+.glyphicon-collapse-down:before {
+ content: "\e159";
+}
+.glyphicon-collapse-up:before {
+ content: "\e160";
+}
+.glyphicon-log-in:before {
+ content: "\e161";
+}
+.glyphicon-flash:before {
+ content: "\e162";
+}
+.glyphicon-log-out:before {
+ content: "\e163";
+}
+.glyphicon-new-window:before {
+ content: "\e164";
+}
+.glyphicon-record:before {
+ content: "\e165";
+}
+.glyphicon-save:before {
+ content: "\e166";
+}
+.glyphicon-open:before {
+ content: "\e167";
+}
+.glyphicon-saved:before {
+ content: "\e168";
+}
+.glyphicon-import:before {
+ content: "\e169";
+}
+.glyphicon-export:before {
+ content: "\e170";
+}
+.glyphicon-send:before {
+ content: "\e171";
+}
+.glyphicon-floppy-disk:before {
+ content: "\e172";
+}
+.glyphicon-floppy-saved:before {
+ content: "\e173";
+}
+.glyphicon-floppy-remove:before {
+ content: "\e174";
+}
+.glyphicon-floppy-save:before {
+ content: "\e175";
+}
+.glyphicon-floppy-open:before {
+ content: "\e176";
+}
+.glyphicon-credit-card:before {
+ content: "\e177";
+}
+.glyphicon-transfer:before {
+ content: "\e178";
+}
+.glyphicon-cutlery:before {
+ content: "\e179";
+}
+.glyphicon-header:before {
+ content: "\e180";
+}
+.glyphicon-compressed:before {
+ content: "\e181";
+}
+.glyphicon-earphone:before {
+ content: "\e182";
+}
+.glyphicon-phone-alt:before {
+ content: "\e183";
+}
+.glyphicon-tower:before {
+ content: "\e184";
+}
+.glyphicon-stats:before {
+ content: "\e185";
+}
+.glyphicon-sd-video:before {
+ content: "\e186";
+}
+.glyphicon-hd-video:before {
+ content: "\e187";
+}
+.glyphicon-subtitles:before {
+ content: "\e188";
+}
+.glyphicon-sound-stereo:before {
+ content: "\e189";
+}
+.glyphicon-sound-dolby:before {
+ content: "\e190";
+}
+.glyphicon-sound-5-1:before {
+ content: "\e191";
+}
+.glyphicon-sound-6-1:before {
+ content: "\e192";
+}
+.glyphicon-sound-7-1:before {
+ content: "\e193";
+}
+.glyphicon-copyright-mark:before {
+ content: "\e194";
+}
+.glyphicon-registration-mark:before {
+ content: "\e195";
+}
+.glyphicon-cloud-download:before {
+ content: "\e197";
+}
+.glyphicon-cloud-upload:before {
+ content: "\e198";
+}
+.glyphicon-tree-conifer:before {
+ content: "\e199";
+}
+.glyphicon-tree-deciduous:before {
+ content: "\e200";
+}
+.glyphicon-cd:before {
+ content: "\e201";
+}
+.glyphicon-save-file:before {
+ content: "\e202";
+}
+.glyphicon-open-file:before {
+ content: "\e203";
+}
+.glyphicon-level-up:before {
+ content: "\e204";
+}
+.glyphicon-copy:before {
+ content: "\e205";
+}
+.glyphicon-paste:before {
+ content: "\e206";
+}
+.glyphicon-alert:before {
+ content: "\e209";
+}
+.glyphicon-equalizer:before {
+ content: "\e210";
+}
+.glyphicon-king:before {
+ content: "\e211";
+}
+.glyphicon-queen:before {
+ content: "\e212";
+}
+.glyphicon-pawn:before {
+ content: "\e213";
+}
+.glyphicon-bishop:before {
+ content: "\e214";
+}
+.glyphicon-knight:before {
+ content: "\e215";
+}
+.glyphicon-baby-formula:before {
+ content: "\e216";
+}
+.glyphicon-tent:before {
+ content: "\26fa";
+}
+.glyphicon-blackboard:before {
+ content: "\e218";
+}
+.glyphicon-bed:before {
+ content: "\e219";
+}
+.glyphicon-apple:before {
+ content: "\f8ff";
+}
+.glyphicon-erase:before {
+ content: "\e221";
+}
+.glyphicon-hourglass:before {
+ content: "\231b";
+}
+.glyphicon-lamp:before {
+ content: "\e223";
+}
+.glyphicon-duplicate:before {
+ content: "\e224";
+}
+.glyphicon-piggy-bank:before {
+ content: "\e225";
+}
+.glyphicon-scissors:before {
+ content: "\e226";
+}
+.glyphicon-bitcoin:before {
+ content: "\e227";
+}
+.glyphicon-btc:before {
+ content: "\e227";
+}
+.glyphicon-xbt:before {
+ content: "\e227";
+}
+.glyphicon-yen:before {
+ content: "\00a5";
+}
+.glyphicon-jpy:before {
+ content: "\00a5";
+}
+.glyphicon-ruble:before {
+ content: "\20bd";
+}
+.glyphicon-rub:before {
+ content: "\20bd";
+}
+.glyphicon-scale:before {
+ content: "\e230";
+}
+.glyphicon-ice-lolly:before {
+ content: "\e231";
+}
+.glyphicon-ice-lolly-tasted:before {
+ content: "\e232";
+}
+.glyphicon-education:before {
+ content: "\e233";
+}
+.glyphicon-option-horizontal:before {
+ content: "\e234";
+}
+.glyphicon-option-vertical:before {
+ content: "\e235";
+}
+.glyphicon-menu-hamburger:before {
+ content: "\e236";
+}
+.glyphicon-modal-window:before {
+ content: "\e237";
+}
+.glyphicon-oil:before {
+ content: "\e238";
+}
+.glyphicon-grain:before {
+ content: "\e239";
+}
+.glyphicon-sunglasses:before {
+ content: "\e240";
+}
+.glyphicon-text-size:before {
+ content: "\e241";
+}
+.glyphicon-text-color:before {
+ content: "\e242";
+}
+.glyphicon-text-background:before {
+ content: "\e243";
+}
+.glyphicon-object-align-top:before {
+ content: "\e244";
+}
+.glyphicon-object-align-bottom:before {
+ content: "\e245";
+}
+.glyphicon-object-align-horizontal:before {
+ content: "\e246";
+}
+.glyphicon-object-align-left:before {
+ content: "\e247";
+}
+.glyphicon-object-align-vertical:before {
+ content: "\e248";
+}
+.glyphicon-object-align-right:before {
+ content: "\e249";
+}
+.glyphicon-triangle-right:before {
+ content: "\e250";
+}
+.glyphicon-triangle-left:before {
+ content: "\e251";
+}
+.glyphicon-triangle-bottom:before {
+ content: "\e252";
+}
+.glyphicon-triangle-top:before {
+ content: "\e253";
+}
+.glyphicon-console:before {
+ content: "\e254";
+}
+.glyphicon-superscript:before {
+ content: "\e255";
+}
+.glyphicon-subscript:before {
+ content: "\e256";
+}
+.glyphicon-menu-left:before {
+ content: "\e257";
+}
+.glyphicon-menu-right:before {
+ content: "\e258";
+}
+.glyphicon-menu-down:before {
+ content: "\e259";
+}
+.glyphicon-menu-up:before {
+ content: "\e260";
+}
+* {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+*:before,
+*:after {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+html {
+ font-size: 10px;
+
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+body {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #333;
+ background-color: #fff;
+}
+input,
+button,
+select,
+textarea {
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+a {
+ color: #337ab7;
+ text-decoration: none;
+}
+a:hover,
+a:focus {
+ color: #23527c;
+ text-decoration: underline;
+}
+a:focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+figure {
+ margin: 0;
+}
+img {
+ vertical-align: middle;
+}
+.img-responsive,
+.thumbnail > img,
+.thumbnail a > img,
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+ display: block;
+ max-width: 100%;
+ height: auto;
+}
+.img-rounded {
+ border-radius: 6px;
+}
+.img-thumbnail {
+ display: inline-block;
+ max-width: 100%;
+ height: auto;
+ padding: 4px;
+ line-height: 1.42857143;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ -webkit-transition: all .2s ease-in-out;
+ -o-transition: all .2s ease-in-out;
+ transition: all .2s ease-in-out;
+}
+.img-circle {
+ border-radius: 50%;
+}
+hr {
+ margin-top: 20px;
+ margin-bottom: 20px;
+ border: 0;
+ border-top: 1px solid #eee;
+}
+.sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ border: 0;
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+ position: static;
+ width: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ clip: auto;
+}
+[role="button"] {
+ cursor: pointer;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+ font-family: inherit;
+ font-weight: 500;
+ line-height: 1.1;
+ color: inherit;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small,
+.h1 small,
+.h2 small,
+.h3 small,
+.h4 small,
+.h5 small,
+.h6 small,
+h1 .small,
+h2 .small,
+h3 .small,
+h4 .small,
+h5 .small,
+h6 .small,
+.h1 .small,
+.h2 .small,
+.h3 .small,
+.h4 .small,
+.h5 .small,
+.h6 .small {
+ font-weight: normal;
+ line-height: 1;
+ color: #777;
+}
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3 {
+ margin-top: 20px;
+ margin-bottom: 10px;
+}
+h1 small,
+.h1 small,
+h2 small,
+.h2 small,
+h3 small,
+.h3 small,
+h1 .small,
+.h1 .small,
+h2 .small,
+.h2 .small,
+h3 .small,
+.h3 .small {
+ font-size: 65%;
+}
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6 {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+h4 small,
+.h4 small,
+h5 small,
+.h5 small,
+h6 small,
+.h6 small,
+h4 .small,
+.h4 .small,
+h5 .small,
+.h5 .small,
+h6 .small,
+.h6 .small {
+ font-size: 75%;
+}
+h1,
+.h1 {
+ font-size: 36px;
+}
+h2,
+.h2 {
+ font-size: 30px;
+}
+h3,
+.h3 {
+ font-size: 24px;
+}
+h4,
+.h4 {
+ font-size: 18px;
+}
+h5,
+.h5 {
+ font-size: 14px;
+}
+h6,
+.h6 {
+ font-size: 12px;
+}
+p {
+ margin: 0 0 10px;
+}
+.lead {
+ margin-bottom: 20px;
+ font-size: 16px;
+ font-weight: 300;
+ line-height: 1.4;
+}
+@media (min-width: 768px) {
+ .lead {
+ font-size: 21px;
+ }
+}
+small,
+.small {
+ font-size: 85%;
+}
+mark,
+.mark {
+ padding: .2em;
+ background-color: #fcf8e3;
+}
+.text-left {
+ text-align: left;
+}
+.text-right {
+ text-align: right;
+}
+.text-center {
+ text-align: center;
+}
+.text-justify {
+ text-align: justify;
+}
+.text-nowrap {
+ white-space: nowrap;
+}
+.text-lowercase {
+ text-transform: lowercase;
+}
+.text-uppercase {
+ text-transform: uppercase;
+}
+.text-capitalize {
+ text-transform: capitalize;
+}
+.text-muted {
+ color: #777;
+}
+.text-primary {
+ color: #337ab7;
+}
+a.text-primary:hover,
+a.text-primary:focus {
+ color: #286090;
+}
+.text-success {
+ color: #3c763d;
+}
+a.text-success:hover,
+a.text-success:focus {
+ color: #2b542c;
+}
+.text-info {
+ color: #31708f;
+}
+a.text-info:hover,
+a.text-info:focus {
+ color: #245269;
+}
+.text-warning {
+ color: #8a6d3b;
+}
+a.text-warning:hover,
+a.text-warning:focus {
+ color: #66512c;
+}
+.text-danger {
+ color: #a94442;
+}
+a.text-danger:hover,
+a.text-danger:focus {
+ color: #843534;
+}
+.bg-primary {
+ color: #fff;
+ background-color: #337ab7;
+}
+a.bg-primary:hover,
+a.bg-primary:focus {
+ background-color: #286090;
+}
+.bg-success {
+ background-color: #dff0d8;
+}
+a.bg-success:hover,
+a.bg-success:focus {
+ background-color: #c1e2b3;
+}
+.bg-info {
+ background-color: #d9edf7;
+}
+a.bg-info:hover,
+a.bg-info:focus {
+ background-color: #afd9ee;
+}
+.bg-warning {
+ background-color: #fcf8e3;
+}
+a.bg-warning:hover,
+a.bg-warning:focus {
+ background-color: #f7ecb5;
+}
+.bg-danger {
+ background-color: #f2dede;
+}
+a.bg-danger:hover,
+a.bg-danger:focus {
+ background-color: #e4b9b9;
+}
+.page-header {
+ padding-bottom: 9px;
+ margin: 40px 0 20px;
+ border-bottom: 1px solid #eee;
+}
+ul,
+ol {
+ margin-top: 0;
+ margin-bottom: 10px;
+}
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+ margin-bottom: 0;
+}
+.list-unstyled {
+ padding-left: 0;
+ list-style: none;
+}
+.list-inline {
+ padding-left: 0;
+ margin-left: -5px;
+ list-style: none;
+}
+.list-inline > li {
+ display: inline-block;
+ padding-right: 5px;
+ padding-left: 5px;
+}
+dl {
+ margin-top: 0;
+ margin-bottom: 20px;
+}
+dt,
+dd {
+ line-height: 1.42857143;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin-left: 0;
+}
+@media (min-width: 768px) {
+ .dl-horizontal dt {
+ float: left;
+ width: 160px;
+ overflow: hidden;
+ clear: left;
+ text-align: right;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .dl-horizontal dd {
+ margin-left: 180px;
+ }
+}
+abbr[title],
+abbr[data-original-title] {
+ cursor: help;
+ border-bottom: 1px dotted #777;
+}
+.initialism {
+ font-size: 90%;
+ text-transform: uppercase;
+}
+blockquote {
+ padding: 10px 20px;
+ margin: 0 0 20px;
+ font-size: 17.5px;
+ border-left: 5px solid #eee;
+}
+blockquote p:last-child,
+blockquote ul:last-child,
+blockquote ol:last-child {
+ margin-bottom: 0;
+}
+blockquote footer,
+blockquote small,
+blockquote .small {
+ display: block;
+ font-size: 80%;
+ line-height: 1.42857143;
+ color: #777;
+}
+blockquote footer:before,
+blockquote small:before,
+blockquote .small:before {
+ content: '\2014 \00A0';
+}
+.blockquote-reverse,
+blockquote.pull-right {
+ padding-right: 15px;
+ padding-left: 0;
+ text-align: right;
+ border-right: 5px solid #eee;
+ border-left: 0;
+}
+.blockquote-reverse footer:before,
+blockquote.pull-right footer:before,
+.blockquote-reverse small:before,
+blockquote.pull-right small:before,
+.blockquote-reverse .small:before,
+blockquote.pull-right .small:before {
+ content: '';
+}
+.blockquote-reverse footer:after,
+blockquote.pull-right footer:after,
+.blockquote-reverse small:after,
+blockquote.pull-right small:after,
+.blockquote-reverse .small:after,
+blockquote.pull-right .small:after {
+ content: '\00A0 \2014';
+}
+address {
+ margin-bottom: 20px;
+ font-style: normal;
+ line-height: 1.42857143;
+}
+code,
+kbd,
+pre,
+samp {
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+}
+code {
+ padding: 2px 4px;
+ font-size: 90%;
+ color: #c7254e;
+ background-color: #f9f2f4;
+ border-radius: 4px;
+}
+kbd {
+ padding: 2px 4px;
+ font-size: 90%;
+ color: #fff;
+ background-color: #333;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
+}
+kbd kbd {
+ padding: 0;
+ font-size: 100%;
+ font-weight: bold;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+pre {
+ display: block;
+ padding: 9.5px;
+ margin: 0 0 10px;
+ font-size: 13px;
+ line-height: 1.42857143;
+ color: #333;
+ word-break: break-all;
+ word-wrap: break-word;
+ background-color: #f5f5f5;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+}
+pre code {
+ padding: 0;
+ font-size: inherit;
+ color: inherit;
+ white-space: pre-wrap;
+ background-color: transparent;
+ border-radius: 0;
+}
+.pre-scrollable {
+ max-height: 340px;
+ overflow-y: scroll;
+}
+.container {
+ padding-right: 15px;
+ padding-left: 15px;
+ margin-right: auto;
+ margin-left: auto;
+}
+@media (min-width: 768px) {
+ .container {
+ width: 750px;
+ }
+}
+@media (min-width: 992px) {
+ .container {
+ width: 970px;
+ }
+}
+@media (min-width: 1200px) {
+ .container {
+ width: 1170px;
+ }
+}
+.container-fluid {
+ padding-right: 15px;
+ padding-left: 15px;
+ margin-right: auto;
+ margin-left: auto;
+}
+.row {
+ margin-right: -15px;
+ margin-left: -15px;
+}
+.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
+ position: relative;
+ min-height: 1px;
+ padding-right: 15px;
+ padding-left: 15px;
+}
+.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
+ float: left;
+}
+.col-xs-12 {
+ width: 100%;
+}
+.col-xs-11 {
+ width: 91.66666667%;
+}
+.col-xs-10 {
+ width: 83.33333333%;
+}
+.col-xs-9 {
+ width: 75%;
+}
+.col-xs-8 {
+ width: 66.66666667%;
+}
+.col-xs-7 {
+ width: 58.33333333%;
+}
+.col-xs-6 {
+ width: 50%;
+}
+.col-xs-5 {
+ width: 41.66666667%;
+}
+.col-xs-4 {
+ width: 33.33333333%;
+}
+.col-xs-3 {
+ width: 25%;
+}
+.col-xs-2 {
+ width: 16.66666667%;
+}
+.col-xs-1 {
+ width: 8.33333333%;
+}
+.col-xs-pull-12 {
+ right: 100%;
+}
+.col-xs-pull-11 {
+ right: 91.66666667%;
+}
+.col-xs-pull-10 {
+ right: 83.33333333%;
+}
+.col-xs-pull-9 {
+ right: 75%;
+}
+.col-xs-pull-8 {
+ right: 66.66666667%;
+}
+.col-xs-pull-7 {
+ right: 58.33333333%;
+}
+.col-xs-pull-6 {
+ right: 50%;
+}
+.col-xs-pull-5 {
+ right: 41.66666667%;
+}
+.col-xs-pull-4 {
+ right: 33.33333333%;
+}
+.col-xs-pull-3 {
+ right: 25%;
+}
+.col-xs-pull-2 {
+ right: 16.66666667%;
+}
+.col-xs-pull-1 {
+ right: 8.33333333%;
+}
+.col-xs-pull-0 {
+ right: auto;
+}
+.col-xs-push-12 {
+ left: 100%;
+}
+.col-xs-push-11 {
+ left: 91.66666667%;
+}
+.col-xs-push-10 {
+ left: 83.33333333%;
+}
+.col-xs-push-9 {
+ left: 75%;
+}
+.col-xs-push-8 {
+ left: 66.66666667%;
+}
+.col-xs-push-7 {
+ left: 58.33333333%;
+}
+.col-xs-push-6 {
+ left: 50%;
+}
+.col-xs-push-5 {
+ left: 41.66666667%;
+}
+.col-xs-push-4 {
+ left: 33.33333333%;
+}
+.col-xs-push-3 {
+ left: 25%;
+}
+.col-xs-push-2 {
+ left: 16.66666667%;
+}
+.col-xs-push-1 {
+ left: 8.33333333%;
+}
+.col-xs-push-0 {
+ left: auto;
+}
+.col-xs-offset-12 {
+ margin-left: 100%;
+}
+.col-xs-offset-11 {
+ margin-left: 91.66666667%;
+}
+.col-xs-offset-10 {
+ margin-left: 83.33333333%;
+}
+.col-xs-offset-9 {
+ margin-left: 75%;
+}
+.col-xs-offset-8 {
+ margin-left: 66.66666667%;
+}
+.col-xs-offset-7 {
+ margin-left: 58.33333333%;
+}
+.col-xs-offset-6 {
+ margin-left: 50%;
+}
+.col-xs-offset-5 {
+ margin-left: 41.66666667%;
+}
+.col-xs-offset-4 {
+ margin-left: 33.33333333%;
+}
+.col-xs-offset-3 {
+ margin-left: 25%;
+}
+.col-xs-offset-2 {
+ margin-left: 16.66666667%;
+}
+.col-xs-offset-1 {
+ margin-left: 8.33333333%;
+}
+.col-xs-offset-0 {
+ margin-left: 0;
+}
+@media (min-width: 768px) {
+ .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
+ float: left;
+ }
+ .col-sm-12 {
+ width: 100%;
+ }
+ .col-sm-11 {
+ width: 91.66666667%;
+ }
+ .col-sm-10 {
+ width: 83.33333333%;
+ }
+ .col-sm-9 {
+ width: 75%;
+ }
+ .col-sm-8 {
+ width: 66.66666667%;
+ }
+ .col-sm-7 {
+ width: 58.33333333%;
+ }
+ .col-sm-6 {
+ width: 50%;
+ }
+ .col-sm-5 {
+ width: 41.66666667%;
+ }
+ .col-sm-4 {
+ width: 33.33333333%;
+ }
+ .col-sm-3 {
+ width: 25%;
+ }
+ .col-sm-2 {
+ width: 16.66666667%;
+ }
+ .col-sm-1 {
+ width: 8.33333333%;
+ }
+ .col-sm-pull-12 {
+ right: 100%;
+ }
+ .col-sm-pull-11 {
+ right: 91.66666667%;
+ }
+ .col-sm-pull-10 {
+ right: 83.33333333%;
+ }
+ .col-sm-pull-9 {
+ right: 75%;
+ }
+ .col-sm-pull-8 {
+ right: 66.66666667%;
+ }
+ .col-sm-pull-7 {
+ right: 58.33333333%;
+ }
+ .col-sm-pull-6 {
+ right: 50%;
+ }
+ .col-sm-pull-5 {
+ right: 41.66666667%;
+ }
+ .col-sm-pull-4 {
+ right: 33.33333333%;
+ }
+ .col-sm-pull-3 {
+ right: 25%;
+ }
+ .col-sm-pull-2 {
+ right: 16.66666667%;
+ }
+ .col-sm-pull-1 {
+ right: 8.33333333%;
+ }
+ .col-sm-pull-0 {
+ right: auto;
+ }
+ .col-sm-push-12 {
+ left: 100%;
+ }
+ .col-sm-push-11 {
+ left: 91.66666667%;
+ }
+ .col-sm-push-10 {
+ left: 83.33333333%;
+ }
+ .col-sm-push-9 {
+ left: 75%;
+ }
+ .col-sm-push-8 {
+ left: 66.66666667%;
+ }
+ .col-sm-push-7 {
+ left: 58.33333333%;
+ }
+ .col-sm-push-6 {
+ left: 50%;
+ }
+ .col-sm-push-5 {
+ left: 41.66666667%;
+ }
+ .col-sm-push-4 {
+ left: 33.33333333%;
+ }
+ .col-sm-push-3 {
+ left: 25%;
+ }
+ .col-sm-push-2 {
+ left: 16.66666667%;
+ }
+ .col-sm-push-1 {
+ left: 8.33333333%;
+ }
+ .col-sm-push-0 {
+ left: auto;
+ }
+ .col-sm-offset-12 {
+ margin-left: 100%;
+ }
+ .col-sm-offset-11 {
+ margin-left: 91.66666667%;
+ }
+ .col-sm-offset-10 {
+ margin-left: 83.33333333%;
+ }
+ .col-sm-offset-9 {
+ margin-left: 75%;
+ }
+ .col-sm-offset-8 {
+ margin-left: 66.66666667%;
+ }
+ .col-sm-offset-7 {
+ margin-left: 58.33333333%;
+ }
+ .col-sm-offset-6 {
+ margin-left: 50%;
+ }
+ .col-sm-offset-5 {
+ margin-left: 41.66666667%;
+ }
+ .col-sm-offset-4 {
+ margin-left: 33.33333333%;
+ }
+ .col-sm-offset-3 {
+ margin-left: 25%;
+ }
+ .col-sm-offset-2 {
+ margin-left: 16.66666667%;
+ }
+ .col-sm-offset-1 {
+ margin-left: 8.33333333%;
+ }
+ .col-sm-offset-0 {
+ margin-left: 0;
+ }
+}
+@media (min-width: 992px) {
+ .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
+ float: left;
+ }
+ .col-md-12 {
+ width: 100%;
+ }
+ .col-md-11 {
+ width: 91.66666667%;
+ }
+ .col-md-10 {
+ width: 83.33333333%;
+ }
+ .col-md-9 {
+ width: 75%;
+ }
+ .col-md-8 {
+ width: 66.66666667%;
+ }
+ .col-md-7 {
+ width: 58.33333333%;
+ }
+ .col-md-6 {
+ width: 50%;
+ }
+ .col-md-5 {
+ width: 41.66666667%;
+ }
+ .col-md-4 {
+ width: 33.33333333%;
+ }
+ .col-md-3 {
+ width: 25%;
+ }
+ .col-md-2 {
+ width: 16.66666667%;
+ }
+ .col-md-1 {
+ width: 8.33333333%;
+ }
+ .col-md-pull-12 {
+ right: 100%;
+ }
+ .col-md-pull-11 {
+ right: 91.66666667%;
+ }
+ .col-md-pull-10 {
+ right: 83.33333333%;
+ }
+ .col-md-pull-9 {
+ right: 75%;
+ }
+ .col-md-pull-8 {
+ right: 66.66666667%;
+ }
+ .col-md-pull-7 {
+ right: 58.33333333%;
+ }
+ .col-md-pull-6 {
+ right: 50%;
+ }
+ .col-md-pull-5 {
+ right: 41.66666667%;
+ }
+ .col-md-pull-4 {
+ right: 33.33333333%;
+ }
+ .col-md-pull-3 {
+ right: 25%;
+ }
+ .col-md-pull-2 {
+ right: 16.66666667%;
+ }
+ .col-md-pull-1 {
+ right: 8.33333333%;
+ }
+ .col-md-pull-0 {
+ right: auto;
+ }
+ .col-md-push-12 {
+ left: 100%;
+ }
+ .col-md-push-11 {
+ left: 91.66666667%;
+ }
+ .col-md-push-10 {
+ left: 83.33333333%;
+ }
+ .col-md-push-9 {
+ left: 75%;
+ }
+ .col-md-push-8 {
+ left: 66.66666667%;
+ }
+ .col-md-push-7 {
+ left: 58.33333333%;
+ }
+ .col-md-push-6 {
+ left: 50%;
+ }
+ .col-md-push-5 {
+ left: 41.66666667%;
+ }
+ .col-md-push-4 {
+ left: 33.33333333%;
+ }
+ .col-md-push-3 {
+ left: 25%;
+ }
+ .col-md-push-2 {
+ left: 16.66666667%;
+ }
+ .col-md-push-1 {
+ left: 8.33333333%;
+ }
+ .col-md-push-0 {
+ left: auto;
+ }
+ .col-md-offset-12 {
+ margin-left: 100%;
+ }
+ .col-md-offset-11 {
+ margin-left: 91.66666667%;
+ }
+ .col-md-offset-10 {
+ margin-left: 83.33333333%;
+ }
+ .col-md-offset-9 {
+ margin-left: 75%;
+ }
+ .col-md-offset-8 {
+ margin-left: 66.66666667%;
+ }
+ .col-md-offset-7 {
+ margin-left: 58.33333333%;
+ }
+ .col-md-offset-6 {
+ margin-left: 50%;
+ }
+ .col-md-offset-5 {
+ margin-left: 41.66666667%;
+ }
+ .col-md-offset-4 {
+ margin-left: 33.33333333%;
+ }
+ .col-md-offset-3 {
+ margin-left: 25%;
+ }
+ .col-md-offset-2 {
+ margin-left: 16.66666667%;
+ }
+ .col-md-offset-1 {
+ margin-left: 8.33333333%;
+ }
+ .col-md-offset-0 {
+ margin-left: 0;
+ }
+}
+@media (min-width: 1200px) {
+ .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
+ float: left;
+ }
+ .col-lg-12 {
+ width: 100%;
+ }
+ .col-lg-11 {
+ width: 91.66666667%;
+ }
+ .col-lg-10 {
+ width: 83.33333333%;
+ }
+ .col-lg-9 {
+ width: 75%;
+ }
+ .col-lg-8 {
+ width: 66.66666667%;
+ }
+ .col-lg-7 {
+ width: 58.33333333%;
+ }
+ .col-lg-6 {
+ width: 50%;
+ }
+ .col-lg-5 {
+ width: 41.66666667%;
+ }
+ .col-lg-4 {
+ width: 33.33333333%;
+ }
+ .col-lg-3 {
+ width: 25%;
+ }
+ .col-lg-2 {
+ width: 16.66666667%;
+ }
+ .col-lg-1 {
+ width: 8.33333333%;
+ }
+ .col-lg-pull-12 {
+ right: 100%;
+ }
+ .col-lg-pull-11 {
+ right: 91.66666667%;
+ }
+ .col-lg-pull-10 {
+ right: 83.33333333%;
+ }
+ .col-lg-pull-9 {
+ right: 75%;
+ }
+ .col-lg-pull-8 {
+ right: 66.66666667%;
+ }
+ .col-lg-pull-7 {
+ right: 58.33333333%;
+ }
+ .col-lg-pull-6 {
+ right: 50%;
+ }
+ .col-lg-pull-5 {
+ right: 41.66666667%;
+ }
+ .col-lg-pull-4 {
+ right: 33.33333333%;
+ }
+ .col-lg-pull-3 {
+ right: 25%;
+ }
+ .col-lg-pull-2 {
+ right: 16.66666667%;
+ }
+ .col-lg-pull-1 {
+ right: 8.33333333%;
+ }
+ .col-lg-pull-0 {
+ right: auto;
+ }
+ .col-lg-push-12 {
+ left: 100%;
+ }
+ .col-lg-push-11 {
+ left: 91.66666667%;
+ }
+ .col-lg-push-10 {
+ left: 83.33333333%;
+ }
+ .col-lg-push-9 {
+ left: 75%;
+ }
+ .col-lg-push-8 {
+ left: 66.66666667%;
+ }
+ .col-lg-push-7 {
+ left: 58.33333333%;
+ }
+ .col-lg-push-6 {
+ left: 50%;
+ }
+ .col-lg-push-5 {
+ left: 41.66666667%;
+ }
+ .col-lg-push-4 {
+ left: 33.33333333%;
+ }
+ .col-lg-push-3 {
+ left: 25%;
+ }
+ .col-lg-push-2 {
+ left: 16.66666667%;
+ }
+ .col-lg-push-1 {
+ left: 8.33333333%;
+ }
+ .col-lg-push-0 {
+ left: auto;
+ }
+ .col-lg-offset-12 {
+ margin-left: 100%;
+ }
+ .col-lg-offset-11 {
+ margin-left: 91.66666667%;
+ }
+ .col-lg-offset-10 {
+ margin-left: 83.33333333%;
+ }
+ .col-lg-offset-9 {
+ margin-left: 75%;
+ }
+ .col-lg-offset-8 {
+ margin-left: 66.66666667%;
+ }
+ .col-lg-offset-7 {
+ margin-left: 58.33333333%;
+ }
+ .col-lg-offset-6 {
+ margin-left: 50%;
+ }
+ .col-lg-offset-5 {
+ margin-left: 41.66666667%;
+ }
+ .col-lg-offset-4 {
+ margin-left: 33.33333333%;
+ }
+ .col-lg-offset-3 {
+ margin-left: 25%;
+ }
+ .col-lg-offset-2 {
+ margin-left: 16.66666667%;
+ }
+ .col-lg-offset-1 {
+ margin-left: 8.33333333%;
+ }
+ .col-lg-offset-0 {
+ margin-left: 0;
+ }
+}
+table {
+ background-color: transparent;
+}
+caption {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ color: #777;
+ text-align: left;
+}
+th {
+ text-align: left;
+}
+.table {
+ width: 100%;
+ max-width: 100%;
+ margin-bottom: 20px;
+}
+.table > thead > tr > th,
+.table > tbody > tr > th,
+.table > tfoot > tr > th,
+.table > thead > tr > td,
+.table > tbody > tr > td,
+.table > tfoot > tr > td {
+ padding: 8px;
+ line-height: 1.42857143;
+ vertical-align: top;
+ border-top: 1px solid #ddd;
+}
+.table > thead > tr > th {
+ vertical-align: bottom;
+ border-bottom: 2px solid #ddd;
+}
+.table > caption + thead > tr:first-child > th,
+.table > colgroup + thead > tr:first-child > th,
+.table > thead:first-child > tr:first-child > th,
+.table > caption + thead > tr:first-child > td,
+.table > colgroup + thead > tr:first-child > td,
+.table > thead:first-child > tr:first-child > td {
+ border-top: 0;
+}
+.table > tbody + tbody {
+ border-top: 2px solid #ddd;
+}
+.table .table {
+ background-color: #fff;
+}
+.table-condensed > thead > tr > th,
+.table-condensed > tbody > tr > th,
+.table-condensed > tfoot > tr > th,
+.table-condensed > thead > tr > td,
+.table-condensed > tbody > tr > td,
+.table-condensed > tfoot > tr > td {
+ padding: 5px;
+}
+.table-bordered {
+ border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > tbody > tr > th,
+.table-bordered > tfoot > tr > th,
+.table-bordered > thead > tr > td,
+.table-bordered > tbody > tr > td,
+.table-bordered > tfoot > tr > td {
+ border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > thead > tr > td {
+ border-bottom-width: 2px;
+}
+.table-striped > tbody > tr:nth-of-type(odd) {
+ background-color: #f9f9f9;
+}
+.table-hover > tbody > tr:hover {
+ background-color: #f5f5f5;
+}
+table col[class*="col-"] {
+ position: static;
+ display: table-column;
+ float: none;
+}
+table td[class*="col-"],
+table th[class*="col-"] {
+ position: static;
+ display: table-cell;
+ float: none;
+}
+.table > thead > tr > td.active,
+.table > tbody > tr > td.active,
+.table > tfoot > tr > td.active,
+.table > thead > tr > th.active,
+.table > tbody > tr > th.active,
+.table > tfoot > tr > th.active,
+.table > thead > tr.active > td,
+.table > tbody > tr.active > td,
+.table > tfoot > tr.active > td,
+.table > thead > tr.active > th,
+.table > tbody > tr.active > th,
+.table > tfoot > tr.active > th {
+ background-color: #f5f5f5;
+}
+.table-hover > tbody > tr > td.active:hover,
+.table-hover > tbody > tr > th.active:hover,
+.table-hover > tbody > tr.active:hover > td,
+.table-hover > tbody > tr:hover > .active,
+.table-hover > tbody > tr.active:hover > th {
+ background-color: #e8e8e8;
+}
+.table > thead > tr > td.success,
+.table > tbody > tr > td.success,
+.table > tfoot > tr > td.success,
+.table > thead > tr > th.success,
+.table > tbody > tr > th.success,
+.table > tfoot > tr > th.success,
+.table > thead > tr.success > td,
+.table > tbody > tr.success > td,
+.table > tfoot > tr.success > td,
+.table > thead > tr.success > th,
+.table > tbody > tr.success > th,
+.table > tfoot > tr.success > th {
+ background-color: #dff0d8;
+}
+.table-hover > tbody > tr > td.success:hover,
+.table-hover > tbody > tr > th.success:hover,
+.table-hover > tbody > tr.success:hover > td,
+.table-hover > tbody > tr:hover > .success,
+.table-hover > tbody > tr.success:hover > th {
+ background-color: #d0e9c6;
+}
+.table > thead > tr > td.info,
+.table > tbody > tr > td.info,
+.table > tfoot > tr > td.info,
+.table > thead > tr > th.info,
+.table > tbody > tr > th.info,
+.table > tfoot > tr > th.info,
+.table > thead > tr.info > td,
+.table > tbody > tr.info > td,
+.table > tfoot > tr.info > td,
+.table > thead > tr.info > th,
+.table > tbody > tr.info > th,
+.table > tfoot > tr.info > th {
+ background-color: #d9edf7;
+}
+.table-hover > tbody > tr > td.info:hover,
+.table-hover > tbody > tr > th.info:hover,
+.table-hover > tbody > tr.info:hover > td,
+.table-hover > tbody > tr:hover > .info,
+.table-hover > tbody > tr.info:hover > th {
+ background-color: #c4e3f3;
+}
+.table > thead > tr > td.warning,
+.table > tbody > tr > td.warning,
+.table > tfoot > tr > td.warning,
+.table > thead > tr > th.warning,
+.table > tbody > tr > th.warning,
+.table > tfoot > tr > th.warning,
+.table > thead > tr.warning > td,
+.table > tbody > tr.warning > td,
+.table > tfoot > tr.warning > td,
+.table > thead > tr.warning > th,
+.table > tbody > tr.warning > th,
+.table > tfoot > tr.warning > th {
+ background-color: #fcf8e3;
+}
+.table-hover > tbody > tr > td.warning:hover,
+.table-hover > tbody > tr > th.warning:hover,
+.table-hover > tbody > tr.warning:hover > td,
+.table-hover > tbody > tr:hover > .warning,
+.table-hover > tbody > tr.warning:hover > th {
+ background-color: #faf2cc;
+}
+.table > thead > tr > td.danger,
+.table > tbody > tr > td.danger,
+.table > tfoot > tr > td.danger,
+.table > thead > tr > th.danger,
+.table > tbody > tr > th.danger,
+.table > tfoot > tr > th.danger,
+.table > thead > tr.danger > td,
+.table > tbody > tr.danger > td,
+.table > tfoot > tr.danger > td,
+.table > thead > tr.danger > th,
+.table > tbody > tr.danger > th,
+.table > tfoot > tr.danger > th {
+ background-color: #f2dede;
+}
+.table-hover > tbody > tr > td.danger:hover,
+.table-hover > tbody > tr > th.danger:hover,
+.table-hover > tbody > tr.danger:hover > td,
+.table-hover > tbody > tr:hover > .danger,
+.table-hover > tbody > tr.danger:hover > th {
+ background-color: #ebcccc;
+}
+.table-responsive {
+ min-height: .01%;
+ overflow-x: auto;
+}
+@media screen and (max-width: 767px) {
+ .table-responsive {
+ width: 100%;
+ margin-bottom: 15px;
+ overflow-y: hidden;
+ -ms-overflow-style: -ms-autohiding-scrollbar;
+ border: 1px solid #ddd;
+ }
+ .table-responsive > .table {
+ margin-bottom: 0;
+ }
+ .table-responsive > .table > thead > tr > th,
+ .table-responsive > .table > tbody > tr > th,
+ .table-responsive > .table > tfoot > tr > th,
+ .table-responsive > .table > thead > tr > td,
+ .table-responsive > .table > tbody > tr > td,
+ .table-responsive > .table > tfoot > tr > td {
+ white-space: nowrap;
+ }
+ .table-responsive > .table-bordered {
+ border: 0;
+ }
+ .table-responsive > .table-bordered > thead > tr > th:first-child,
+ .table-responsive > .table-bordered > tbody > tr > th:first-child,
+ .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+ .table-responsive > .table-bordered > thead > tr > td:first-child,
+ .table-responsive > .table-bordered > tbody > tr > td:first-child,
+ .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+ border-left: 0;
+ }
+ .table-responsive > .table-bordered > thead > tr > th:last-child,
+ .table-responsive > .table-bordered > tbody > tr > th:last-child,
+ .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+ .table-responsive > .table-bordered > thead > tr > td:last-child,
+ .table-responsive > .table-bordered > tbody > tr > td:last-child,
+ .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+ border-right: 0;
+ }
+ .table-responsive > .table-bordered > tbody > tr:last-child > th,
+ .table-responsive > .table-bordered > tfoot > tr:last-child > th,
+ .table-responsive > .table-bordered > tbody > tr:last-child > td,
+ .table-responsive > .table-bordered > tfoot > tr:last-child > td {
+ border-bottom: 0;
+ }
+}
+fieldset {
+ min-width: 0;
+ padding: 0;
+ margin: 0;
+ border: 0;
+}
+legend {
+ display: block;
+ width: 100%;
+ padding: 0;
+ margin-bottom: 20px;
+ font-size: 21px;
+ line-height: inherit;
+ color: #333;
+ border: 0;
+ border-bottom: 1px solid #e5e5e5;
+}
+label {
+ display: inline-block;
+ max-width: 100%;
+ margin-bottom: 5px;
+ font-weight: bold;
+}
+input[type="search"] {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+input[type="radio"],
+input[type="checkbox"] {
+ margin: 4px 0 0;
+ margin-top: 1px \9;
+ line-height: normal;
+}
+input[type="file"] {
+ display: block;
+}
+input[type="range"] {
+ display: block;
+ width: 100%;
+}
+select[multiple],
+select[size] {
+ height: auto;
+}
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+output {
+ display: block;
+ padding-top: 7px;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #555;
+}
+.form-control {
+ display: block;
+ width: 100%;
+ height: 34px;
+ padding: 6px 12px;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #555;
+ background-color: #fff;
+ background-image: none;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
+ -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+ transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+}
+.form-control:focus {
+ border-color: #66afe9;
+ outline: 0;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
+}
+.form-control::-moz-placeholder {
+ color: #999;
+ opacity: 1;
+}
+.form-control:-ms-input-placeholder {
+ color: #999;
+}
+.form-control::-webkit-input-placeholder {
+ color: #999;
+}
+.form-control[disabled],
+.form-control[readonly],
+fieldset[disabled] .form-control {
+ background-color: #eee;
+ opacity: 1;
+}
+.form-control[disabled],
+fieldset[disabled] .form-control {
+ cursor: not-allowed;
+}
+textarea.form-control {
+ height: auto;
+}
+input[type="search"] {
+ -webkit-appearance: none;
+}
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+ input[type="date"].form-control,
+ input[type="time"].form-control,
+ input[type="datetime-local"].form-control,
+ input[type="month"].form-control {
+ line-height: 34px;
+ }
+ input[type="date"].input-sm,
+ input[type="time"].input-sm,
+ input[type="datetime-local"].input-sm,
+ input[type="month"].input-sm,
+ .input-group-sm input[type="date"],
+ .input-group-sm input[type="time"],
+ .input-group-sm input[type="datetime-local"],
+ .input-group-sm input[type="month"] {
+ line-height: 30px;
+ }
+ input[type="date"].input-lg,
+ input[type="time"].input-lg,
+ input[type="datetime-local"].input-lg,
+ input[type="month"].input-lg,
+ .input-group-lg input[type="date"],
+ .input-group-lg input[type="time"],
+ .input-group-lg input[type="datetime-local"],
+ .input-group-lg input[type="month"] {
+ line-height: 46px;
+ }
+}
+.form-group {
+ margin-bottom: 15px;
+}
+.radio,
+.checkbox {
+ position: relative;
+ display: block;
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+.radio label,
+.checkbox label {
+ min-height: 20px;
+ padding-left: 20px;
+ margin-bottom: 0;
+ font-weight: normal;
+ cursor: pointer;
+}
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+ position: absolute;
+ margin-top: 4px \9;
+ margin-left: -20px;
+}
+.radio + .radio,
+.checkbox + .checkbox {
+ margin-top: -5px;
+}
+.radio-inline,
+.checkbox-inline {
+ position: relative;
+ display: inline-block;
+ padding-left: 20px;
+ margin-bottom: 0;
+ font-weight: normal;
+ vertical-align: middle;
+ cursor: pointer;
+}
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+ margin-top: 0;
+ margin-left: 10px;
+}
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"].disabled,
+input[type="checkbox"].disabled,
+fieldset[disabled] input[type="radio"],
+fieldset[disabled] input[type="checkbox"] {
+ cursor: not-allowed;
+}
+.radio-inline.disabled,
+.checkbox-inline.disabled,
+fieldset[disabled] .radio-inline,
+fieldset[disabled] .checkbox-inline {
+ cursor: not-allowed;
+}
+.radio.disabled label,
+.checkbox.disabled label,
+fieldset[disabled] .radio label,
+fieldset[disabled] .checkbox label {
+ cursor: not-allowed;
+}
+.form-control-static {
+ min-height: 34px;
+ padding-top: 7px;
+ padding-bottom: 7px;
+ margin-bottom: 0;
+}
+.form-control-static.input-lg,
+.form-control-static.input-sm {
+ padding-right: 0;
+ padding-left: 0;
+}
+.input-sm {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+select.input-sm {
+ height: 30px;
+ line-height: 30px;
+}
+textarea.input-sm,
+select[multiple].input-sm {
+ height: auto;
+}
+.form-group-sm .form-control {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+.form-group-sm select.form-control {
+ height: 30px;
+ line-height: 30px;
+}
+.form-group-sm textarea.form-control,
+.form-group-sm select[multiple].form-control {
+ height: auto;
+}
+.form-group-sm .form-control-static {
+ height: 30px;
+ min-height: 32px;
+ padding: 6px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+}
+.input-lg {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+select.input-lg {
+ height: 46px;
+ line-height: 46px;
+}
+textarea.input-lg,
+select[multiple].input-lg {
+ height: auto;
+}
+.form-group-lg .form-control {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+.form-group-lg select.form-control {
+ height: 46px;
+ line-height: 46px;
+}
+.form-group-lg textarea.form-control,
+.form-group-lg select[multiple].form-control {
+ height: auto;
+}
+.form-group-lg .form-control-static {
+ height: 46px;
+ min-height: 38px;
+ padding: 11px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+}
+.has-feedback {
+ position: relative;
+}
+.has-feedback .form-control {
+ padding-right: 42.5px;
+}
+.form-control-feedback {
+ position: absolute;
+ top: 0;
+ right: 0;
+ z-index: 2;
+ display: block;
+ width: 34px;
+ height: 34px;
+ line-height: 34px;
+ text-align: center;
+ pointer-events: none;
+}
+.input-lg + .form-control-feedback,
+.input-group-lg + .form-control-feedback,
+.form-group-lg .form-control + .form-control-feedback {
+ width: 46px;
+ height: 46px;
+ line-height: 46px;
+}
+.input-sm + .form-control-feedback,
+.input-group-sm + .form-control-feedback,
+.form-group-sm .form-control + .form-control-feedback {
+ width: 30px;
+ height: 30px;
+ line-height: 30px;
+}
+.has-success .help-block,
+.has-success .control-label,
+.has-success .radio,
+.has-success .checkbox,
+.has-success .radio-inline,
+.has-success .checkbox-inline,
+.has-success.radio label,
+.has-success.checkbox label,
+.has-success.radio-inline label,
+.has-success.checkbox-inline label {
+ color: #3c763d;
+}
+.has-success .form-control {
+ border-color: #3c763d;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-success .form-control:focus {
+ border-color: #2b542c;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
+}
+.has-success .input-group-addon {
+ color: #3c763d;
+ background-color: #dff0d8;
+ border-color: #3c763d;
+}
+.has-success .form-control-feedback {
+ color: #3c763d;
+}
+.has-warning .help-block,
+.has-warning .control-label,
+.has-warning .radio,
+.has-warning .checkbox,
+.has-warning .radio-inline,
+.has-warning .checkbox-inline,
+.has-warning.radio label,
+.has-warning.checkbox label,
+.has-warning.radio-inline label,
+.has-warning.checkbox-inline label {
+ color: #8a6d3b;
+}
+.has-warning .form-control {
+ border-color: #8a6d3b;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-warning .form-control:focus {
+ border-color: #66512c;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
+}
+.has-warning .input-group-addon {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+ border-color: #8a6d3b;
+}
+.has-warning .form-control-feedback {
+ color: #8a6d3b;
+}
+.has-error .help-block,
+.has-error .control-label,
+.has-error .radio,
+.has-error .checkbox,
+.has-error .radio-inline,
+.has-error .checkbox-inline,
+.has-error.radio label,
+.has-error.checkbox label,
+.has-error.radio-inline label,
+.has-error.checkbox-inline label {
+ color: #a94442;
+}
+.has-error .form-control {
+ border-color: #a94442;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-error .form-control:focus {
+ border-color: #843534;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
+}
+.has-error .input-group-addon {
+ color: #a94442;
+ background-color: #f2dede;
+ border-color: #a94442;
+}
+.has-error .form-control-feedback {
+ color: #a94442;
+}
+.has-feedback label ~ .form-control-feedback {
+ top: 25px;
+}
+.has-feedback label.sr-only ~ .form-control-feedback {
+ top: 0;
+}
+.help-block {
+ display: block;
+ margin-top: 5px;
+ margin-bottom: 10px;
+ color: #737373;
+}
+@media (min-width: 768px) {
+ .form-inline .form-group {
+ display: inline-block;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .form-control {
+ display: inline-block;
+ width: auto;
+ vertical-align: middle;
+ }
+ .form-inline .form-control-static {
+ display: inline-block;
+ }
+ .form-inline .input-group {
+ display: inline-table;
+ vertical-align: middle;
+ }
+ .form-inline .input-group .input-group-addon,
+ .form-inline .input-group .input-group-btn,
+ .form-inline .input-group .form-control {
+ width: auto;
+ }
+ .form-inline .input-group > .form-control {
+ width: 100%;
+ }
+ .form-inline .control-label {
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .radio,
+ .form-inline .checkbox {
+ display: inline-block;
+ margin-top: 0;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .radio label,
+ .form-inline .checkbox label {
+ padding-left: 0;
+ }
+ .form-inline .radio input[type="radio"],
+ .form-inline .checkbox input[type="checkbox"] {
+ position: relative;
+ margin-left: 0;
+ }
+ .form-inline .has-feedback .form-control-feedback {
+ top: 0;
+ }
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox,
+.form-horizontal .radio-inline,
+.form-horizontal .checkbox-inline {
+ padding-top: 7px;
+ margin-top: 0;
+ margin-bottom: 0;
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox {
+ min-height: 27px;
+}
+.form-horizontal .form-group {
+ margin-right: -15px;
+ margin-left: -15px;
+}
+@media (min-width: 768px) {
+ .form-horizontal .control-label {
+ padding-top: 7px;
+ margin-bottom: 0;
+ text-align: right;
+ }
+}
+.form-horizontal .has-feedback .form-control-feedback {
+ right: 15px;
+}
+@media (min-width: 768px) {
+ .form-horizontal .form-group-lg .control-label {
+ padding-top: 14.333333px;
+ font-size: 18px;
+ }
+}
+@media (min-width: 768px) {
+ .form-horizontal .form-group-sm .control-label {
+ padding-top: 6px;
+ font-size: 12px;
+ }
+}
+.btn {
+ display: inline-block;
+ padding: 6px 12px;
+ margin-bottom: 0;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 1.42857143;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ -ms-touch-action: manipulation;
+ touch-action: manipulation;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ background-image: none;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+.btn:focus,
+.btn:active:focus,
+.btn.active:focus,
+.btn.focus,
+.btn:active.focus,
+.btn.active.focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+.btn:hover,
+.btn:focus,
+.btn.focus {
+ color: #333;
+ text-decoration: none;
+}
+.btn:active,
+.btn.active {
+ background-image: none;
+ outline: 0;
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn.disabled,
+.btn[disabled],
+fieldset[disabled] .btn {
+ cursor: not-allowed;
+ filter: alpha(opacity=65);
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ opacity: .65;
+}
+a.btn.disabled,
+fieldset[disabled] a.btn {
+ pointer-events: none;
+}
+.btn-default {
+ color: #333;
+ background-color: #fff;
+ border-color: #ccc;
+}
+.btn-default:focus,
+.btn-default.focus {
+ color: #333;
+ background-color: #e6e6e6;
+ border-color: #8c8c8c;
+}
+.btn-default:hover {
+ color: #333;
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+ color: #333;
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+.btn-default:active:hover,
+.btn-default.active:hover,
+.open > .dropdown-toggle.btn-default:hover,
+.btn-default:active:focus,
+.btn-default.active:focus,
+.open > .dropdown-toggle.btn-default:focus,
+.btn-default:active.focus,
+.btn-default.active.focus,
+.open > .dropdown-toggle.btn-default.focus {
+ color: #333;
+ background-color: #d4d4d4;
+ border-color: #8c8c8c;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+ background-image: none;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+fieldset[disabled] .btn-default,
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus,
+.btn-default.disabled:active,
+.btn-default[disabled]:active,
+fieldset[disabled] .btn-default:active,
+.btn-default.disabled.active,
+.btn-default[disabled].active,
+fieldset[disabled] .btn-default.active {
+ background-color: #fff;
+ border-color: #ccc;
+}
+.btn-default .badge {
+ color: #fff;
+ background-color: #333;
+}
+.btn-primary {
+ color: #fff;
+ background-color: #337ab7;
+ border-color: #2e6da4;
+}
+.btn-primary:focus,
+.btn-primary.focus {
+ color: #fff;
+ background-color: #286090;
+ border-color: #122b40;
+}
+.btn-primary:hover {
+ color: #fff;
+ background-color: #286090;
+ border-color: #204d74;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+ color: #fff;
+ background-color: #286090;
+ border-color: #204d74;
+}
+.btn-primary:active:hover,
+.btn-primary.active:hover,
+.open > .dropdown-toggle.btn-primary:hover,
+.btn-primary:active:focus,
+.btn-primary.active:focus,
+.open > .dropdown-toggle.btn-primary:focus,
+.btn-primary:active.focus,
+.btn-primary.active.focus,
+.open > .dropdown-toggle.btn-primary.focus {
+ color: #fff;
+ background-color: #204d74;
+ border-color: #122b40;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+ background-image: none;
+}
+.btn-primary.disabled,
+.btn-primary[disabled],
+fieldset[disabled] .btn-primary,
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus,
+.btn-primary.disabled:active,
+.btn-primary[disabled]:active,
+fieldset[disabled] .btn-primary:active,
+.btn-primary.disabled.active,
+.btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active {
+ background-color: #337ab7;
+ border-color: #2e6da4;
+}
+.btn-primary .badge {
+ color: #337ab7;
+ background-color: #fff;
+}
+.btn-success {
+ color: #fff;
+ background-color: #5cb85c;
+ border-color: #4cae4c;
+}
+.btn-success:focus,
+.btn-success.focus {
+ color: #fff;
+ background-color: #449d44;
+ border-color: #255625;
+}
+.btn-success:hover {
+ color: #fff;
+ background-color: #449d44;
+ border-color: #398439;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+ color: #fff;
+ background-color: #449d44;
+ border-color: #398439;
+}
+.btn-success:active:hover,
+.btn-success.active:hover,
+.open > .dropdown-toggle.btn-success:hover,
+.btn-success:active:focus,
+.btn-success.active:focus,
+.open > .dropdown-toggle.btn-success:focus,
+.btn-success:active.focus,
+.btn-success.active.focus,
+.open > .dropdown-toggle.btn-success.focus {
+ color: #fff;
+ background-color: #398439;
+ border-color: #255625;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+ background-image: none;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+fieldset[disabled] .btn-success,
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus,
+.btn-success.disabled:active,
+.btn-success[disabled]:active,
+fieldset[disabled] .btn-success:active,
+.btn-success.disabled.active,
+.btn-success[disabled].active,
+fieldset[disabled] .btn-success.active {
+ background-color: #5cb85c;
+ border-color: #4cae4c;
+}
+.btn-success .badge {
+ color: #5cb85c;
+ background-color: #fff;
+}
+.btn-info {
+ color: #fff;
+ background-color: #5bc0de;
+ border-color: #46b8da;
+}
+.btn-info:focus,
+.btn-info.focus {
+ color: #fff;
+ background-color: #31b0d5;
+ border-color: #1b6d85;
+}
+.btn-info:hover {
+ color: #fff;
+ background-color: #31b0d5;
+ border-color: #269abc;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+ color: #fff;
+ background-color: #31b0d5;
+ border-color: #269abc;
+}
+.btn-info:active:hover,
+.btn-info.active:hover,
+.open > .dropdown-toggle.btn-info:hover,
+.btn-info:active:focus,
+.btn-info.active:focus,
+.open > .dropdown-toggle.btn-info:focus,
+.btn-info:active.focus,
+.btn-info.active.focus,
+.open > .dropdown-toggle.btn-info.focus {
+ color: #fff;
+ background-color: #269abc;
+ border-color: #1b6d85;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+ background-image: none;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+fieldset[disabled] .btn-info,
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus,
+.btn-info.disabled:active,
+.btn-info[disabled]:active,
+fieldset[disabled] .btn-info:active,
+.btn-info.disabled.active,
+.btn-info[disabled].active,
+fieldset[disabled] .btn-info.active {
+ background-color: #5bc0de;
+ border-color: #46b8da;
+}
+.btn-info .badge {
+ color: #5bc0de;
+ background-color: #fff;
+}
+.btn-warning {
+ color: #fff;
+ background-color: #f0ad4e;
+ border-color: #eea236;
+}
+.btn-warning:focus,
+.btn-warning.focus {
+ color: #fff;
+ background-color: #ec971f;
+ border-color: #985f0d;
+}
+.btn-warning:hover {
+ color: #fff;
+ background-color: #ec971f;
+ border-color: #d58512;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+ color: #fff;
+ background-color: #ec971f;
+ border-color: #d58512;
+}
+.btn-warning:active:hover,
+.btn-warning.active:hover,
+.open > .dropdown-toggle.btn-warning:hover,
+.btn-warning:active:focus,
+.btn-warning.active:focus,
+.open > .dropdown-toggle.btn-warning:focus,
+.btn-warning:active.focus,
+.btn-warning.active.focus,
+.open > .dropdown-toggle.btn-warning.focus {
+ color: #fff;
+ background-color: #d58512;
+ border-color: #985f0d;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+ background-image: none;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+fieldset[disabled] .btn-warning,
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus,
+.btn-warning.disabled:active,
+.btn-warning[disabled]:active,
+fieldset[disabled] .btn-warning:active,
+.btn-warning.disabled.active,
+.btn-warning[disabled].active,
+fieldset[disabled] .btn-warning.active {
+ background-color: #f0ad4e;
+ border-color: #eea236;
+}
+.btn-warning .badge {
+ color: #f0ad4e;
+ background-color: #fff;
+}
+.btn-danger {
+ color: #fff;
+ background-color: #d9534f;
+ border-color: #d43f3a;
+}
+.btn-danger:focus,
+.btn-danger.focus {
+ color: #fff;
+ background-color: #c9302c;
+ border-color: #761c19;
+}
+.btn-danger:hover {
+ color: #fff;
+ background-color: #c9302c;
+ border-color: #ac2925;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+ color: #fff;
+ background-color: #c9302c;
+ border-color: #ac2925;
+}
+.btn-danger:active:hover,
+.btn-danger.active:hover,
+.open > .dropdown-toggle.btn-danger:hover,
+.btn-danger:active:focus,
+.btn-danger.active:focus,
+.open > .dropdown-toggle.btn-danger:focus,
+.btn-danger:active.focus,
+.btn-danger.active.focus,
+.open > .dropdown-toggle.btn-danger.focus {
+ color: #fff;
+ background-color: #ac2925;
+ border-color: #761c19;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+ background-image: none;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+fieldset[disabled] .btn-danger,
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus,
+.btn-danger.disabled:active,
+.btn-danger[disabled]:active,
+fieldset[disabled] .btn-danger:active,
+.btn-danger.disabled.active,
+.btn-danger[disabled].active,
+fieldset[disabled] .btn-danger.active {
+ background-color: #d9534f;
+ border-color: #d43f3a;
+}
+.btn-danger .badge {
+ color: #d9534f;
+ background-color: #fff;
+}
+.btn-link {
+ font-weight: normal;
+ color: #337ab7;
+ border-radius: 0;
+}
+.btn-link,
+.btn-link:active,
+.btn-link.active,
+.btn-link[disabled],
+fieldset[disabled] .btn-link {
+ background-color: transparent;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.btn-link,
+.btn-link:hover,
+.btn-link:focus,
+.btn-link:active {
+ border-color: transparent;
+}
+.btn-link:hover,
+.btn-link:focus {
+ color: #23527c;
+ text-decoration: underline;
+ background-color: transparent;
+}
+.btn-link[disabled]:hover,
+fieldset[disabled] .btn-link:hover,
+.btn-link[disabled]:focus,
+fieldset[disabled] .btn-link:focus {
+ color: #777;
+ text-decoration: none;
+}
+.btn-lg,
+.btn-group-lg > .btn {
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+.btn-sm,
+.btn-group-sm > .btn {
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+.btn-xs,
+.btn-group-xs > .btn {
+ padding: 1px 5px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+.btn-block {
+ display: block;
+ width: 100%;
+}
+.btn-block + .btn-block {
+ margin-top: 5px;
+}
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+ width: 100%;
+}
+.fade {
+ opacity: 0;
+ -webkit-transition: opacity .15s linear;
+ -o-transition: opacity .15s linear;
+ transition: opacity .15s linear;
+}
+.fade.in {
+ opacity: 1;
+}
+.collapse {
+ display: none;
+}
+.collapse.in {
+ display: block;
+}
+tr.collapse.in {
+ display: table-row;
+}
+tbody.collapse.in {
+ display: table-row-group;
+}
+.collapsing {
+ position: relative;
+ height: 0;
+ overflow: hidden;
+ -webkit-transition-timing-function: ease;
+ -o-transition-timing-function: ease;
+ transition-timing-function: ease;
+ -webkit-transition-duration: .35s;
+ -o-transition-duration: .35s;
+ transition-duration: .35s;
+ -webkit-transition-property: height, visibility;
+ -o-transition-property: height, visibility;
+ transition-property: height, visibility;
+}
+.caret {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-left: 2px;
+ vertical-align: middle;
+ border-top: 4px dashed;
+ border-top: 4px solid \9;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+}
+.dropup,
+.dropdown {
+ position: relative;
+}
+.dropdown-toggle:focus {
+ outline: 0;
+}
+.dropdown-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: 1000;
+ display: none;
+ float: left;
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 2px 0 0;
+ font-size: 14px;
+ text-align: left;
+ list-style: none;
+ background-color: #fff;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, .15);
+ border-radius: 4px;
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+}
+.dropdown-menu.pull-right {
+ right: 0;
+ left: auto;
+}
+.dropdown-menu .divider {
+ height: 1px;
+ margin: 9px 0;
+ overflow: hidden;
+ background-color: #e5e5e5;
+}
+.dropdown-menu > li > a {
+ display: block;
+ padding: 3px 20px;
+ clear: both;
+ font-weight: normal;
+ line-height: 1.42857143;
+ color: #333;
+ white-space: nowrap;
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ color: #262626;
+ text-decoration: none;
+ background-color: #f5f5f5;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ color: #fff;
+ text-decoration: none;
+ background-color: #337ab7;
+ outline: 0;
+}
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ color: #777;
+}
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+ text-decoration: none;
+ cursor: not-allowed;
+ background-color: transparent;
+ background-image: none;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+.open > .dropdown-menu {
+ display: block;
+}
+.open > a {
+ outline: 0;
+}
+.dropdown-menu-right {
+ right: 0;
+ left: auto;
+}
+.dropdown-menu-left {
+ right: auto;
+ left: 0;
+}
+.dropdown-header {
+ display: block;
+ padding: 3px 20px;
+ font-size: 12px;
+ line-height: 1.42857143;
+ color: #777;
+ white-space: nowrap;
+}
+.dropdown-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 990;
+}
+.pull-right > .dropdown-menu {
+ right: 0;
+ left: auto;
+}
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+ content: "";
+ border-top: 0;
+ border-bottom: 4px dashed;
+ border-bottom: 4px solid \9;
+}
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+ top: auto;
+ bottom: 100%;
+ margin-bottom: 2px;
+}
+@media (min-width: 768px) {
+ .navbar-right .dropdown-menu {
+ right: 0;
+ left: auto;
+ }
+ .navbar-right .dropdown-menu-left {
+ right: auto;
+ left: 0;
+ }
+}
+.btn-group,
+.btn-group-vertical {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+}
+.btn-group > .btn,
+.btn-group-vertical > .btn {
+ position: relative;
+ float: left;
+}
+.btn-group > .btn:hover,
+.btn-group-vertical > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group-vertical > .btn:focus,
+.btn-group > .btn:active,
+.btn-group-vertical > .btn:active,
+.btn-group > .btn.active,
+.btn-group-vertical > .btn.active {
+ z-index: 2;
+}
+.btn-group .btn + .btn,
+.btn-group .btn + .btn-group,
+.btn-group .btn-group + .btn,
+.btn-group .btn-group + .btn-group {
+ margin-left: -1px;
+}
+.btn-toolbar {
+ margin-left: -5px;
+}
+.btn-toolbar .btn,
+.btn-toolbar .btn-group,
+.btn-toolbar .input-group {
+ float: left;
+}
+.btn-toolbar > .btn,
+.btn-toolbar > .btn-group,
+.btn-toolbar > .input-group {
+ margin-left: 5px;
+}
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+ border-radius: 0;
+}
+.btn-group > .btn:first-child {
+ margin-left: 0;
+}
+.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group > .btn-group {
+ float: left;
+}
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+ border-radius: 0;
+}
+.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+ outline: 0;
+}
+.btn-group > .btn + .dropdown-toggle {
+ padding-right: 8px;
+ padding-left: 8px;
+}
+.btn-group > .btn-lg + .dropdown-toggle {
+ padding-right: 12px;
+ padding-left: 12px;
+}
+.btn-group.open .dropdown-toggle {
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-group.open .dropdown-toggle.btn-link {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.btn .caret {
+ margin-left: 0;
+}
+.btn-lg .caret {
+ border-width: 5px 5px 0;
+ border-bottom-width: 0;
+}
+.dropup .btn-lg .caret {
+ border-width: 0 5px 5px;
+}
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group,
+.btn-group-vertical > .btn-group > .btn {
+ display: block;
+ float: none;
+ width: 100%;
+ max-width: 100%;
+}
+.btn-group-vertical > .btn-group > .btn {
+ float: none;
+}
+.btn-group-vertical > .btn + .btn,
+.btn-group-vertical > .btn + .btn-group,
+.btn-group-vertical > .btn-group + .btn,
+.btn-group-vertical > .btn-group + .btn-group {
+ margin-top: -1px;
+ margin-left: 0;
+}
+.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
+ border-radius: 0;
+}
+.btn-group-vertical > .btn:first-child:not(:last-child) {
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn:last-child:not(:first-child) {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-left-radius: 4px;
+}
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+ border-radius: 0;
+}
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+.btn-group-justified {
+ display: table;
+ width: 100%;
+ table-layout: fixed;
+ border-collapse: separate;
+}
+.btn-group-justified > .btn,
+.btn-group-justified > .btn-group {
+ display: table-cell;
+ float: none;
+ width: 1%;
+}
+.btn-group-justified > .btn-group .btn {
+ width: 100%;
+}
+.btn-group-justified > .btn-group .dropdown-menu {
+ left: auto;
+}
+[data-toggle="buttons"] > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn input[type="checkbox"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
+ position: absolute;
+ clip: rect(0, 0, 0, 0);
+ pointer-events: none;
+}
+.input-group {
+ position: relative;
+ display: table;
+ border-collapse: separate;
+}
+.input-group[class*="col-"] {
+ float: none;
+ padding-right: 0;
+ padding-left: 0;
+}
+.input-group .form-control {
+ position: relative;
+ z-index: 2;
+ float: left;
+ width: 100%;
+ margin-bottom: 0;
+}
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+select.input-group-lg > .form-control,
+select.input-group-lg > .input-group-addon,
+select.input-group-lg > .input-group-btn > .btn {
+ height: 46px;
+ line-height: 46px;
+}
+textarea.input-group-lg > .form-control,
+textarea.input-group-lg > .input-group-addon,
+textarea.input-group-lg > .input-group-btn > .btn,
+select[multiple].input-group-lg > .form-control,
+select[multiple].input-group-lg > .input-group-addon,
+select[multiple].input-group-lg > .input-group-btn > .btn {
+ height: auto;
+}
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+select.input-group-sm > .form-control,
+select.input-group-sm > .input-group-addon,
+select.input-group-sm > .input-group-btn > .btn {
+ height: 30px;
+ line-height: 30px;
+}
+textarea.input-group-sm > .form-control,
+textarea.input-group-sm > .input-group-addon,
+textarea.input-group-sm > .input-group-btn > .btn,
+select[multiple].input-group-sm > .form-control,
+select[multiple].input-group-sm > .input-group-addon,
+select[multiple].input-group-sm > .input-group-btn > .btn {
+ height: auto;
+}
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+ display: table-cell;
+}
+.input-group-addon:not(:first-child):not(:last-child),
+.input-group-btn:not(:first-child):not(:last-child),
+.input-group .form-control:not(:first-child):not(:last-child) {
+ border-radius: 0;
+}
+.input-group-addon,
+.input-group-btn {
+ width: 1%;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+.input-group-addon {
+ padding: 6px 12px;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 1;
+ color: #555;
+ text-align: center;
+ background-color: #eee;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+}
+.input-group-addon.input-sm {
+ padding: 5px 10px;
+ font-size: 12px;
+ border-radius: 3px;
+}
+.input-group-addon.input-lg {
+ padding: 10px 16px;
+ font-size: 18px;
+ border-radius: 6px;
+}
+.input-group-addon input[type="radio"],
+.input-group-addon input[type="checkbox"] {
+ margin-top: 0;
+}
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.input-group-addon:first-child {
+ border-right: 0;
+}
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.input-group-addon:last-child {
+ border-left: 0;
+}
+.input-group-btn {
+ position: relative;
+ font-size: 0;
+ white-space: nowrap;
+}
+.input-group-btn > .btn {
+ position: relative;
+}
+.input-group-btn > .btn + .btn {
+ margin-left: -1px;
+}
+.input-group-btn > .btn:hover,
+.input-group-btn > .btn:focus,
+.input-group-btn > .btn:active {
+ z-index: 2;
+}
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group {
+ margin-right: -1px;
+}
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group {
+ z-index: 2;
+ margin-left: -1px;
+}
+.nav {
+ padding-left: 0;
+ margin-bottom: 0;
+ list-style: none;
+}
+.nav > li {
+ position: relative;
+ display: block;
+}
+.nav > li > a {
+ position: relative;
+ display: block;
+ padding: 10px 15px;
+}
+.nav > li > a:hover,
+.nav > li > a:focus {
+ text-decoration: none;
+ background-color: #eee;
+}
+.nav > li.disabled > a {
+ color: #777;
+}
+.nav > li.disabled > a:hover,
+.nav > li.disabled > a:focus {
+ color: #777;
+ text-decoration: none;
+ cursor: not-allowed;
+ background-color: transparent;
+}
+.nav .open > a,
+.nav .open > a:hover,
+.nav .open > a:focus {
+ background-color: #eee;
+ border-color: #337ab7;
+}
+.nav .nav-divider {
+ height: 1px;
+ margin: 9px 0;
+ overflow: hidden;
+ background-color: #e5e5e5;
+}
+.nav > li > a > img {
+ max-width: none;
+}
+.nav-tabs {
+ border-bottom: 1px solid #ddd;
+}
+.nav-tabs > li {
+ float: left;
+ margin-bottom: -1px;
+}
+.nav-tabs > li > a {
+ margin-right: 2px;
+ line-height: 1.42857143;
+ border: 1px solid transparent;
+ border-radius: 4px 4px 0 0;
+}
+.nav-tabs > li > a:hover {
+ border-color: #eee #eee #ddd;
+}
+.nav-tabs > li.active > a,
+.nav-tabs > li.active > a:hover,
+.nav-tabs > li.active > a:focus {
+ color: #555;
+ cursor: default;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ border-bottom-color: transparent;
+}
+.nav-tabs.nav-justified {
+ width: 100%;
+ border-bottom: 0;
+}
+.nav-tabs.nav-justified > li {
+ float: none;
+}
+.nav-tabs.nav-justified > li > a {
+ margin-bottom: 5px;
+ text-align: center;
+}
+.nav-tabs.nav-justified > .dropdown .dropdown-menu {
+ top: auto;
+ left: auto;
+}
+@media (min-width: 768px) {
+ .nav-tabs.nav-justified > li {
+ display: table-cell;
+ width: 1%;
+ }
+ .nav-tabs.nav-justified > li > a {
+ margin-bottom: 0;
+ }
+}
+.nav-tabs.nav-justified > li > a {
+ margin-right: 0;
+ border-radius: 4px;
+}
+.nav-tabs.nav-justified > .active > a,
+.nav-tabs.nav-justified > .active > a:hover,
+.nav-tabs.nav-justified > .active > a:focus {
+ border: 1px solid #ddd;
+}
+@media (min-width: 768px) {
+ .nav-tabs.nav-justified > li > a {
+ border-bottom: 1px solid #ddd;
+ border-radius: 4px 4px 0 0;
+ }
+ .nav-tabs.nav-justified > .active > a,
+ .nav-tabs.nav-justified > .active > a:hover,
+ .nav-tabs.nav-justified > .active > a:focus {
+ border-bottom-color: #fff;
+ }
+}
+.nav-pills > li {
+ float: left;
+}
+.nav-pills > li > a {
+ border-radius: 4px;
+}
+.nav-pills > li + li {
+ margin-left: 2px;
+}
+.nav-pills > li.active > a,
+.nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+ color: #fff;
+ background-color: #337ab7;
+}
+.nav-stacked > li {
+ float: none;
+}
+.nav-stacked > li + li {
+ margin-top: 2px;
+ margin-left: 0;
+}
+.nav-justified {
+ width: 100%;
+}
+.nav-justified > li {
+ float: none;
+}
+.nav-justified > li > a {
+ margin-bottom: 5px;
+ text-align: center;
+}
+.nav-justified > .dropdown .dropdown-menu {
+ top: auto;
+ left: auto;
+}
+@media (min-width: 768px) {
+ .nav-justified > li {
+ display: table-cell;
+ width: 1%;
+ }
+ .nav-justified > li > a {
+ margin-bottom: 0;
+ }
+}
+.nav-tabs-justified {
+ border-bottom: 0;
+}
+.nav-tabs-justified > li > a {
+ margin-right: 0;
+ border-radius: 4px;
+}
+.nav-tabs-justified > .active > a,
+.nav-tabs-justified > .active > a:hover,
+.nav-tabs-justified > .active > a:focus {
+ border: 1px solid #ddd;
+}
+@media (min-width: 768px) {
+ .nav-tabs-justified > li > a {
+ border-bottom: 1px solid #ddd;
+ border-radius: 4px 4px 0 0;
+ }
+ .nav-tabs-justified > .active > a,
+ .nav-tabs-justified > .active > a:hover,
+ .nav-tabs-justified > .active > a:focus {
+ border-bottom-color: #fff;
+ }
+}
+.tab-content > .tab-pane {
+ display: none;
+}
+.tab-content > .active {
+ display: block;
+}
+.nav-tabs .dropdown-menu {
+ margin-top: -1px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+.navbar {
+ position: relative;
+ min-height: 50px;
+ margin-bottom: 20px;
+ border: 1px solid transparent;
+}
+@media (min-width: 768px) {
+ .navbar {
+ border-radius: 4px;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-header {
+ float: left;
+ }
+}
+.navbar-collapse {
+ padding-right: 15px;
+ padding-left: 15px;
+ overflow-x: visible;
+ -webkit-overflow-scrolling: touch;
+ border-top: 1px solid transparent;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
+}
+.navbar-collapse.in {
+ overflow-y: auto;
+}
+@media (min-width: 768px) {
+ .navbar-collapse {
+ width: auto;
+ border-top: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+ .navbar-collapse.collapse {
+ display: block !important;
+ height: auto !important;
+ padding-bottom: 0;
+ overflow: visible !important;
+ }
+ .navbar-collapse.in {
+ overflow-y: visible;
+ }
+ .navbar-fixed-top .navbar-collapse,
+ .navbar-static-top .navbar-collapse,
+ .navbar-fixed-bottom .navbar-collapse {
+ padding-right: 0;
+ padding-left: 0;
+ }
+}
+.navbar-fixed-top .navbar-collapse,
+.navbar-fixed-bottom .navbar-collapse {
+ max-height: 340px;
+}
+@media (max-device-width: 480px) and (orientation: landscape) {
+ .navbar-fixed-top .navbar-collapse,
+ .navbar-fixed-bottom .navbar-collapse {
+ max-height: 200px;
+ }
+}
+.container > .navbar-header,
+.container-fluid > .navbar-header,
+.container > .navbar-collapse,
+.container-fluid > .navbar-collapse {
+ margin-right: -15px;
+ margin-left: -15px;
+}
+@media (min-width: 768px) {
+ .container > .navbar-header,
+ .container-fluid > .navbar-header,
+ .container > .navbar-collapse,
+ .container-fluid > .navbar-collapse {
+ margin-right: 0;
+ margin-left: 0;
+ }
+}
+.navbar-static-top {
+ z-index: 1000;
+ border-width: 0 0 1px;
+}
+@media (min-width: 768px) {
+ .navbar-static-top {
+ border-radius: 0;
+ }
+}
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ position: fixed;
+ right: 0;
+ left: 0;
+ z-index: 1030;
+}
+@media (min-width: 768px) {
+ .navbar-fixed-top,
+ .navbar-fixed-bottom {
+ border-radius: 0;
+ }
+}
+.navbar-fixed-top {
+ top: 0;
+ border-width: 0 0 1px;
+}
+.navbar-fixed-bottom {
+ bottom: 0;
+ margin-bottom: 0;
+ border-width: 1px 0 0;
+}
+.navbar-brand {
+ float: left;
+ height: 50px;
+ padding: 15px 15px;
+ font-size: 18px;
+ line-height: 20px;
+}
+.navbar-brand:hover,
+.navbar-brand:focus {
+ text-decoration: none;
+}
+.navbar-brand > img {
+ display: block;
+}
+@media (min-width: 768px) {
+ .navbar > .container .navbar-brand,
+ .navbar > .container-fluid .navbar-brand {
+ margin-left: -15px;
+ }
+}
+.navbar-toggle {
+ position: relative;
+ float: right;
+ padding: 9px 10px;
+ margin-top: 8px;
+ margin-right: 15px;
+ margin-bottom: 8px;
+ background-color: transparent;
+ background-image: none;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+.navbar-toggle:focus {
+ outline: 0;
+}
+.navbar-toggle .icon-bar {
+ display: block;
+ width: 22px;
+ height: 2px;
+ border-radius: 1px;
+}
+.navbar-toggle .icon-bar + .icon-bar {
+ margin-top: 4px;
+}
+@media (min-width: 768px) {
+ .navbar-toggle {
+ display: none;
+ }
+}
+.navbar-nav {
+ margin: 7.5px -15px;
+}
+.navbar-nav > li > a {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ line-height: 20px;
+}
+@media (max-width: 767px) {
+ .navbar-nav .open .dropdown-menu {
+ position: static;
+ float: none;
+ width: auto;
+ margin-top: 0;
+ background-color: transparent;
+ border: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+ .navbar-nav .open .dropdown-menu > li > a,
+ .navbar-nav .open .dropdown-menu .dropdown-header {
+ padding: 5px 15px 5px 25px;
+ }
+ .navbar-nav .open .dropdown-menu > li > a {
+ line-height: 20px;
+ }
+ .navbar-nav .open .dropdown-menu > li > a:hover,
+ .navbar-nav .open .dropdown-menu > li > a:focus {
+ background-image: none;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-nav {
+ float: left;
+ margin: 0;
+ }
+ .navbar-nav > li {
+ float: left;
+ }
+ .navbar-nav > li > a {
+ padding-top: 15px;
+ padding-bottom: 15px;
+ }
+}
+.navbar-form {
+ padding: 10px 15px;
+ margin-top: 8px;
+ margin-right: -15px;
+ margin-bottom: 8px;
+ margin-left: -15px;
+ border-top: 1px solid transparent;
+ border-bottom: 1px solid transparent;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
+}
+@media (min-width: 768px) {
+ .navbar-form .form-group {
+ display: inline-block;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .navbar-form .form-control {
+ display: inline-block;
+ width: auto;
+ vertical-align: middle;
+ }
+ .navbar-form .form-control-static {
+ display: inline-block;
+ }
+ .navbar-form .input-group {
+ display: inline-table;
+ vertical-align: middle;
+ }
+ .navbar-form .input-group .input-group-addon,
+ .navbar-form .input-group .input-group-btn,
+ .navbar-form .input-group .form-control {
+ width: auto;
+ }
+ .navbar-form .input-group > .form-control {
+ width: 100%;
+ }
+ .navbar-form .control-label {
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .navbar-form .radio,
+ .navbar-form .checkbox {
+ display: inline-block;
+ margin-top: 0;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+ .navbar-form .radio label,
+ .navbar-form .checkbox label {
+ padding-left: 0;
+ }
+ .navbar-form .radio input[type="radio"],
+ .navbar-form .checkbox input[type="checkbox"] {
+ position: relative;
+ margin-left: 0;
+ }
+ .navbar-form .has-feedback .form-control-feedback {
+ top: 0;
+ }
+}
+@media (max-width: 767px) {
+ .navbar-form .form-group {
+ margin-bottom: 5px;
+ }
+ .navbar-form .form-group:last-child {
+ margin-bottom: 0;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-form {
+ width: auto;
+ padding-top: 0;
+ padding-bottom: 0;
+ margin-right: 0;
+ margin-left: 0;
+ border: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+}
+.navbar-nav > li > .dropdown-menu {
+ margin-top: 0;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+ margin-bottom: 0;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.navbar-btn {
+ margin-top: 8px;
+ margin-bottom: 8px;
+}
+.navbar-btn.btn-sm {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+.navbar-btn.btn-xs {
+ margin-top: 14px;
+ margin-bottom: 14px;
+}
+.navbar-text {
+ margin-top: 15px;
+ margin-bottom: 15px;
+}
+@media (min-width: 768px) {
+ .navbar-text {
+ float: left;
+ margin-right: 15px;
+ margin-left: 15px;
+ }
+}
+@media (min-width: 768px) {
+ .navbar-left {
+ float: left !important;
+ }
+ .navbar-right {
+ float: right !important;
+ margin-right: -15px;
+ }
+ .navbar-right ~ .navbar-right {
+ margin-right: 0;
+ }
+}
+.navbar-default {
+ background-color: #f8f8f8;
+ border-color: #e7e7e7;
+}
+.navbar-default .navbar-brand {
+ color: #777;
+}
+.navbar-default .navbar-brand:hover,
+.navbar-default .navbar-brand:focus {
+ color: #5e5e5e;
+ background-color: transparent;
+}
+.navbar-default .navbar-text {
+ color: #777;
+}
+.navbar-default .navbar-nav > li > a {
+ color: #777;
+}
+.navbar-default .navbar-nav > li > a:hover,
+.navbar-default .navbar-nav > li > a:focus {
+ color: #333;
+ background-color: transparent;
+}
+.navbar-default .navbar-nav > .active > a,
+.navbar-default .navbar-nav > .active > a:hover,
+.navbar-default .navbar-nav > .active > a:focus {
+ color: #555;
+ background-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .disabled > a,
+.navbar-default .navbar-nav > .disabled > a:hover,
+.navbar-default .navbar-nav > .disabled > a:focus {
+ color: #ccc;
+ background-color: transparent;
+}
+.navbar-default .navbar-toggle {
+ border-color: #ddd;
+}
+.navbar-default .navbar-toggle:hover,
+.navbar-default .navbar-toggle:focus {
+ background-color: #ddd;
+}
+.navbar-default .navbar-toggle .icon-bar {
+ background-color: #888;
+}
+.navbar-default .navbar-collapse,
+.navbar-default .navbar-form {
+ border-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .open > a:hover,
+.navbar-default .navbar-nav > .open > a:focus {
+ color: #555;
+ background-color: #e7e7e7;
+}
+@media (max-width: 767px) {
+ .navbar-default .navbar-nav .open .dropdown-menu > li > a {
+ color: #777;
+ }
+ .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
+ .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
+ color: #333;
+ background-color: transparent;
+ }
+ .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
+ .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
+ .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
+ color: #555;
+ background-color: #e7e7e7;
+ }
+ .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
+ .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+ .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+ color: #ccc;
+ background-color: transparent;
+ }
+}
+.navbar-default .navbar-link {
+ color: #777;
+}
+.navbar-default .navbar-link:hover {
+ color: #333;
+}
+.navbar-default .btn-link {
+ color: #777;
+}
+.navbar-default .btn-link:hover,
+.navbar-default .btn-link:focus {
+ color: #333;
+}
+.navbar-default .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-default .btn-link:hover,
+.navbar-default .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-default .btn-link:focus {
+ color: #ccc;
+}
+.navbar-inverse {
+ background-color: #222;
+ border-color: #080808;
+}
+.navbar-inverse .navbar-brand {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-brand:hover,
+.navbar-inverse .navbar-brand:focus {
+ color: #fff;
+ background-color: transparent;
+}
+.navbar-inverse .navbar-text {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a:hover,
+.navbar-inverse .navbar-nav > li > a:focus {
+ color: #fff;
+ background-color: transparent;
+}
+.navbar-inverse .navbar-nav > .active > a,
+.navbar-inverse .navbar-nav > .active > a:hover,
+.navbar-inverse .navbar-nav > .active > a:focus {
+ color: #fff;
+ background-color: #080808;
+}
+.navbar-inverse .navbar-nav > .disabled > a,
+.navbar-inverse .navbar-nav > .disabled > a:hover,
+.navbar-inverse .navbar-nav > .disabled > a:focus {
+ color: #444;
+ background-color: transparent;
+}
+.navbar-inverse .navbar-toggle {
+ border-color: #333;
+}
+.navbar-inverse .navbar-toggle:hover,
+.navbar-inverse .navbar-toggle:focus {
+ background-color: #333;
+}
+.navbar-inverse .navbar-toggle .icon-bar {
+ background-color: #fff;
+}
+.navbar-inverse .navbar-collapse,
+.navbar-inverse .navbar-form {
+ border-color: #101010;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .open > a:hover,
+.navbar-inverse .navbar-nav > .open > a:focus {
+ color: #fff;
+ background-color: #080808;
+}
+@media (max-width: 767px) {
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
+ border-color: #080808;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
+ background-color: #080808;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
+ color: #9d9d9d;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
+ color: #fff;
+ background-color: transparent;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
+ color: #fff;
+ background-color: #080808;
+ }
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+ .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+ color: #444;
+ background-color: transparent;
+ }
+}
+.navbar-inverse .navbar-link {
+ color: #9d9d9d;
+}
+.navbar-inverse .navbar-link:hover {
+ color: #fff;
+}
+.navbar-inverse .btn-link {
+ color: #9d9d9d;
+}
+.navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link:focus {
+ color: #fff;
+}
+.navbar-inverse .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-inverse .btn-link:focus {
+ color: #444;
+}
+.breadcrumb {
+ padding: 8px 15px;
+ margin-bottom: 20px;
+ list-style: none;
+ background-color: #f5f5f5;
+ border-radius: 4px;
+}
+.breadcrumb > li {
+ display: inline-block;
+}
+.breadcrumb > li + li:before {
+ padding: 0 5px;
+ color: #ccc;
+ content: "/\00a0";
+}
+.breadcrumb > .active {
+ color: #777;
+}
+.pagination {
+ display: inline-block;
+ padding-left: 0;
+ margin: 20px 0;
+ border-radius: 4px;
+}
+.pagination > li {
+ display: inline;
+}
+.pagination > li > a,
+.pagination > li > span {
+ position: relative;
+ float: left;
+ padding: 6px 12px;
+ margin-left: -1px;
+ line-height: 1.42857143;
+ color: #337ab7;
+ text-decoration: none;
+ background-color: #fff;
+ border: 1px solid #ddd;
+}
+.pagination > li:first-child > a,
+.pagination > li:first-child > span {
+ margin-left: 0;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+.pagination > li:last-child > a,
+.pagination > li:last-child > span {
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+}
+.pagination > li > a:hover,
+.pagination > li > span:hover,
+.pagination > li > a:focus,
+.pagination > li > span:focus {
+ z-index: 3;
+ color: #23527c;
+ background-color: #eee;
+ border-color: #ddd;
+}
+.pagination > .active > a,
+.pagination > .active > span,
+.pagination > .active > a:hover,
+.pagination > .active > span:hover,
+.pagination > .active > a:focus,
+.pagination > .active > span:focus {
+ z-index: 2;
+ color: #fff;
+ cursor: default;
+ background-color: #337ab7;
+ border-color: #337ab7;
+}
+.pagination > .disabled > span,
+.pagination > .disabled > span:hover,
+.pagination > .disabled > span:focus,
+.pagination > .disabled > a,
+.pagination > .disabled > a:hover,
+.pagination > .disabled > a:focus {
+ color: #777;
+ cursor: not-allowed;
+ background-color: #fff;
+ border-color: #ddd;
+}
+.pagination-lg > li > a,
+.pagination-lg > li > span {
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+}
+.pagination-lg > li:first-child > a,
+.pagination-lg > li:first-child > span {
+ border-top-left-radius: 6px;
+ border-bottom-left-radius: 6px;
+}
+.pagination-lg > li:last-child > a,
+.pagination-lg > li:last-child > span {
+ border-top-right-radius: 6px;
+ border-bottom-right-radius: 6px;
+}
+.pagination-sm > li > a,
+.pagination-sm > li > span {
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+}
+.pagination-sm > li:first-child > a,
+.pagination-sm > li:first-child > span {
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.pagination-sm > li:last-child > a,
+.pagination-sm > li:last-child > span {
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+.pager {
+ padding-left: 0;
+ margin: 20px 0;
+ text-align: center;
+ list-style: none;
+}
+.pager li {
+ display: inline;
+}
+.pager li > a,
+.pager li > span {
+ display: inline-block;
+ padding: 5px 14px;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ border-radius: 15px;
+}
+.pager li > a:hover,
+.pager li > a:focus {
+ text-decoration: none;
+ background-color: #eee;
+}
+.pager .next > a,
+.pager .next > span {
+ float: right;
+}
+.pager .previous > a,
+.pager .previous > span {
+ float: left;
+}
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+ color: #777;
+ cursor: not-allowed;
+ background-color: #fff;
+}
+.label {
+ display: inline;
+ padding: .2em .6em .3em;
+ font-size: 75%;
+ font-weight: bold;
+ line-height: 1;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: .25em;
+}
+a.label:hover,
+a.label:focus {
+ color: #fff;
+ text-decoration: none;
+ cursor: pointer;
+}
+.label:empty {
+ display: none;
+}
+.btn .label {
+ position: relative;
+ top: -1px;
+}
+.label-default {
+ background-color: #777;
+}
+.label-default[href]:hover,
+.label-default[href]:focus {
+ background-color: #5e5e5e;
+}
+.label-primary {
+ background-color: #337ab7;
+}
+.label-primary[href]:hover,
+.label-primary[href]:focus {
+ background-color: #286090;
+}
+.label-success {
+ background-color: #5cb85c;
+}
+.label-success[href]:hover,
+.label-success[href]:focus {
+ background-color: #449d44;
+}
+.label-info {
+ background-color: #5bc0de;
+}
+.label-info[href]:hover,
+.label-info[href]:focus {
+ background-color: #31b0d5;
+}
+.label-warning {
+ background-color: #f0ad4e;
+}
+.label-warning[href]:hover,
+.label-warning[href]:focus {
+ background-color: #ec971f;
+}
+.label-danger {
+ background-color: #d9534f;
+}
+.label-danger[href]:hover,
+.label-danger[href]:focus {
+ background-color: #c9302c;
+}
+.badge {
+ display: inline-block;
+ min-width: 10px;
+ padding: 3px 7px;
+ font-size: 12px;
+ font-weight: bold;
+ line-height: 1;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ background-color: #777;
+ border-radius: 10px;
+}
+.badge:empty {
+ display: none;
+}
+.btn .badge {
+ position: relative;
+ top: -1px;
+}
+.btn-xs .badge,
+.btn-group-xs > .btn .badge {
+ top: 0;
+ padding: 1px 5px;
+}
+a.badge:hover,
+a.badge:focus {
+ color: #fff;
+ text-decoration: none;
+ cursor: pointer;
+}
+.list-group-item.active > .badge,
+.nav-pills > .active > a > .badge {
+ color: #337ab7;
+ background-color: #fff;
+}
+.list-group-item > .badge {
+ float: right;
+}
+.list-group-item > .badge + .badge {
+ margin-right: 5px;
+}
+.nav-pills > li > a > .badge {
+ margin-left: 3px;
+}
+.jumbotron {
+ padding-top: 30px;
+ padding-bottom: 30px;
+ margin-bottom: 30px;
+ color: inherit;
+ background-color: #eee;
+}
+.jumbotron h1,
+.jumbotron .h1 {
+ color: inherit;
+}
+.jumbotron p {
+ margin-bottom: 15px;
+ font-size: 21px;
+ font-weight: 200;
+}
+.jumbotron > hr {
+ border-top-color: #d5d5d5;
+}
+.container .jumbotron,
+.container-fluid .jumbotron {
+ border-radius: 6px;
+}
+.jumbotron .container {
+ max-width: 100%;
+}
+@media screen and (min-width: 768px) {
+ .jumbotron {
+ padding-top: 48px;
+ padding-bottom: 48px;
+ }
+ .container .jumbotron,
+ .container-fluid .jumbotron {
+ padding-right: 60px;
+ padding-left: 60px;
+ }
+ .jumbotron h1,
+ .jumbotron .h1 {
+ font-size: 63px;
+ }
+}
+.thumbnail {
+ display: block;
+ padding: 4px;
+ margin-bottom: 20px;
+ line-height: 1.42857143;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ -webkit-transition: border .2s ease-in-out;
+ -o-transition: border .2s ease-in-out;
+ transition: border .2s ease-in-out;
+}
+.thumbnail > img,
+.thumbnail a > img {
+ margin-right: auto;
+ margin-left: auto;
+}
+a.thumbnail:hover,
+a.thumbnail:focus,
+a.thumbnail.active {
+ border-color: #337ab7;
+}
+.thumbnail .caption {
+ padding: 9px;
+ color: #333;
+}
+.alert {
+ padding: 15px;
+ margin-bottom: 20px;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+.alert h4 {
+ margin-top: 0;
+ color: inherit;
+}
+.alert .alert-link {
+ font-weight: bold;
+}
+.alert > p,
+.alert > ul {
+ margin-bottom: 0;
+}
+.alert > p + p {
+ margin-top: 5px;
+}
+.alert-dismissable,
+.alert-dismissible {
+ padding-right: 35px;
+}
+.alert-dismissable .close,
+.alert-dismissible .close {
+ position: relative;
+ top: -2px;
+ right: -21px;
+ color: inherit;
+}
+.alert-success {
+ color: #3c763d;
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+}
+.alert-success hr {
+ border-top-color: #c9e2b3;
+}
+.alert-success .alert-link {
+ color: #2b542c;
+}
+.alert-info {
+ color: #31708f;
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+}
+.alert-info hr {
+ border-top-color: #a6e1ec;
+}
+.alert-info .alert-link {
+ color: #245269;
+}
+.alert-warning {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+ border-color: #faebcc;
+}
+.alert-warning hr {
+ border-top-color: #f7e1b5;
+}
+.alert-warning .alert-link {
+ color: #66512c;
+}
+.alert-danger {
+ color: #a94442;
+ background-color: #f2dede;
+ border-color: #ebccd1;
+}
+.alert-danger hr {
+ border-top-color: #e4b9c0;
+}
+.alert-danger .alert-link {
+ color: #843534;
+}
+@-webkit-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+@-o-keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+@keyframes progress-bar-stripes {
+ from {
+ background-position: 40px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+.progress {
+ height: 20px;
+ margin-bottom: 20px;
+ overflow: hidden;
+ background-color: #f5f5f5;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+}
+.progress-bar {
+ float: left;
+ width: 0;
+ height: 100%;
+ font-size: 12px;
+ line-height: 20px;
+ color: #fff;
+ text-align: center;
+ background-color: #337ab7;
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
+ -webkit-transition: width .6s ease;
+ -o-transition: width .6s ease;
+ transition: width .6s ease;
+}
+.progress-striped .progress-bar,
+.progress-bar-striped {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ -webkit-background-size: 40px 40px;
+ background-size: 40px 40px;
+}
+.progress.active .progress-bar,
+.progress-bar.active {
+ -webkit-animation: progress-bar-stripes 2s linear infinite;
+ -o-animation: progress-bar-stripes 2s linear infinite;
+ animation: progress-bar-stripes 2s linear infinite;
+}
+.progress-bar-success {
+ background-color: #5cb85c;
+}
+.progress-striped .progress-bar-success {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-info {
+ background-color: #5bc0de;
+}
+.progress-striped .progress-bar-info {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-warning {
+ background-color: #f0ad4e;
+}
+.progress-striped .progress-bar-warning {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-danger {
+ background-color: #d9534f;
+}
+.progress-striped .progress-bar-danger {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.media {
+ margin-top: 15px;
+}
+.media:first-child {
+ margin-top: 0;
+}
+.media,
+.media-body {
+ overflow: hidden;
+ zoom: 1;
+}
+.media-body {
+ width: 10000px;
+}
+.media-object {
+ display: block;
+}
+.media-object.img-thumbnail {
+ max-width: none;
+}
+.media-right,
+.media > .pull-right {
+ padding-left: 10px;
+}
+.media-left,
+.media > .pull-left {
+ padding-right: 10px;
+}
+.media-left,
+.media-right,
+.media-body {
+ display: table-cell;
+ vertical-align: top;
+}
+.media-middle {
+ vertical-align: middle;
+}
+.media-bottom {
+ vertical-align: bottom;
+}
+.media-heading {
+ margin-top: 0;
+ margin-bottom: 5px;
+}
+.media-list {
+ padding-left: 0;
+ list-style: none;
+}
+.list-group {
+ padding-left: 0;
+ margin-bottom: 20px;
+}
+.list-group-item {
+ position: relative;
+ display: block;
+ padding: 10px 15px;
+ margin-bottom: -1px;
+ background-color: #fff;
+ border: 1px solid #ddd;
+}
+.list-group-item:first-child {
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+}
+.list-group-item:last-child {
+ margin-bottom: 0;
+ border-bottom-right-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+a.list-group-item,
+button.list-group-item {
+ color: #555;
+}
+a.list-group-item .list-group-item-heading,
+button.list-group-item .list-group-item-heading {
+ color: #333;
+}
+a.list-group-item:hover,
+button.list-group-item:hover,
+a.list-group-item:focus,
+button.list-group-item:focus {
+ color: #555;
+ text-decoration: none;
+ background-color: #f5f5f5;
+}
+button.list-group-item {
+ width: 100%;
+ text-align: left;
+}
+.list-group-item.disabled,
+.list-group-item.disabled:hover,
+.list-group-item.disabled:focus {
+ color: #777;
+ cursor: not-allowed;
+ background-color: #eee;
+}
+.list-group-item.disabled .list-group-item-heading,
+.list-group-item.disabled:hover .list-group-item-heading,
+.list-group-item.disabled:focus .list-group-item-heading {
+ color: inherit;
+}
+.list-group-item.disabled .list-group-item-text,
+.list-group-item.disabled:hover .list-group-item-text,
+.list-group-item.disabled:focus .list-group-item-text {
+ color: #777;
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+ z-index: 2;
+ color: #fff;
+ background-color: #337ab7;
+ border-color: #337ab7;
+}
+.list-group-item.active .list-group-item-heading,
+.list-group-item.active:hover .list-group-item-heading,
+.list-group-item.active:focus .list-group-item-heading,
+.list-group-item.active .list-group-item-heading > small,
+.list-group-item.active:hover .list-group-item-heading > small,
+.list-group-item.active:focus .list-group-item-heading > small,
+.list-group-item.active .list-group-item-heading > .small,
+.list-group-item.active:hover .list-group-item-heading > .small,
+.list-group-item.active:focus .list-group-item-heading > .small {
+ color: inherit;
+}
+.list-group-item.active .list-group-item-text,
+.list-group-item.active:hover .list-group-item-text,
+.list-group-item.active:focus .list-group-item-text {
+ color: #c7ddef;
+}
+.list-group-item-success {
+ color: #3c763d;
+ background-color: #dff0d8;
+}
+a.list-group-item-success,
+button.list-group-item-success {
+ color: #3c763d;
+}
+a.list-group-item-success .list-group-item-heading,
+button.list-group-item-success .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-success:hover,
+button.list-group-item-success:hover,
+a.list-group-item-success:focus,
+button.list-group-item-success:focus {
+ color: #3c763d;
+ background-color: #d0e9c6;
+}
+a.list-group-item-success.active,
+button.list-group-item-success.active,
+a.list-group-item-success.active:hover,
+button.list-group-item-success.active:hover,
+a.list-group-item-success.active:focus,
+button.list-group-item-success.active:focus {
+ color: #fff;
+ background-color: #3c763d;
+ border-color: #3c763d;
+}
+.list-group-item-info {
+ color: #31708f;
+ background-color: #d9edf7;
+}
+a.list-group-item-info,
+button.list-group-item-info {
+ color: #31708f;
+}
+a.list-group-item-info .list-group-item-heading,
+button.list-group-item-info .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-info:hover,
+button.list-group-item-info:hover,
+a.list-group-item-info:focus,
+button.list-group-item-info:focus {
+ color: #31708f;
+ background-color: #c4e3f3;
+}
+a.list-group-item-info.active,
+button.list-group-item-info.active,
+a.list-group-item-info.active:hover,
+button.list-group-item-info.active:hover,
+a.list-group-item-info.active:focus,
+button.list-group-item-info.active:focus {
+ color: #fff;
+ background-color: #31708f;
+ border-color: #31708f;
+}
+.list-group-item-warning {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+}
+a.list-group-item-warning,
+button.list-group-item-warning {
+ color: #8a6d3b;
+}
+a.list-group-item-warning .list-group-item-heading,
+button.list-group-item-warning .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-warning:hover,
+button.list-group-item-warning:hover,
+a.list-group-item-warning:focus,
+button.list-group-item-warning:focus {
+ color: #8a6d3b;
+ background-color: #faf2cc;
+}
+a.list-group-item-warning.active,
+button.list-group-item-warning.active,
+a.list-group-item-warning.active:hover,
+button.list-group-item-warning.active:hover,
+a.list-group-item-warning.active:focus,
+button.list-group-item-warning.active:focus {
+ color: #fff;
+ background-color: #8a6d3b;
+ border-color: #8a6d3b;
+}
+.list-group-item-danger {
+ color: #a94442;
+ background-color: #f2dede;
+}
+a.list-group-item-danger,
+button.list-group-item-danger {
+ color: #a94442;
+}
+a.list-group-item-danger .list-group-item-heading,
+button.list-group-item-danger .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-danger:hover,
+button.list-group-item-danger:hover,
+a.list-group-item-danger:focus,
+button.list-group-item-danger:focus {
+ color: #a94442;
+ background-color: #ebcccc;
+}
+a.list-group-item-danger.active,
+button.list-group-item-danger.active,
+a.list-group-item-danger.active:hover,
+button.list-group-item-danger.active:hover,
+a.list-group-item-danger.active:focus,
+button.list-group-item-danger.active:focus {
+ color: #fff;
+ background-color: #a94442;
+ border-color: #a94442;
+}
+.list-group-item-heading {
+ margin-top: 0;
+ margin-bottom: 5px;
+}
+.list-group-item-text {
+ margin-bottom: 0;
+ line-height: 1.3;
+}
+.panel {
+ margin-bottom: 20px;
+ background-color: #fff;
+ border: 1px solid transparent;
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+ box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+}
+.panel-body {
+ padding: 15px;
+}
+.panel-heading {
+ padding: 10px 15px;
+ border-bottom: 1px solid transparent;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel-heading > .dropdown .dropdown-toggle {
+ color: inherit;
+}
+.panel-title {
+ margin-top: 0;
+ margin-bottom: 0;
+ font-size: 16px;
+ color: inherit;
+}
+.panel-title > a,
+.panel-title > small,
+.panel-title > .small,
+.panel-title > small > a,
+.panel-title > .small > a {
+ color: inherit;
+}
+.panel-footer {
+ padding: 10px 15px;
+ background-color: #f5f5f5;
+ border-top: 1px solid #ddd;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .list-group,
+.panel > .panel-collapse > .list-group {
+ margin-bottom: 0;
+}
+.panel > .list-group .list-group-item,
+.panel > .panel-collapse > .list-group .list-group-item {
+ border-width: 1px 0;
+ border-radius: 0;
+}
+.panel > .list-group:first-child .list-group-item:first-child,
+.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
+ border-top: 0;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel > .list-group:last-child .list-group-item:last-child,
+.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
+ border-bottom: 0;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+.panel-heading + .list-group .list-group-item:first-child {
+ border-top-width: 0;
+}
+.list-group + .panel-footer {
+ border-top-width: 0;
+}
+.panel > .table,
+.panel > .table-responsive > .table,
+.panel > .panel-collapse > .table {
+ margin-bottom: 0;
+}
+.panel > .table caption,
+.panel > .table-responsive > .table caption,
+.panel > .panel-collapse > .table caption {
+ padding-right: 15px;
+ padding-left: 15px;
+}
+.panel > .table:first-child,
+.panel > .table-responsive:first-child > .table:first-child {
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
+ border-top-left-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
+ border-top-right-radius: 3px;
+}
+.panel > .table:last-child,
+.panel > .table-responsive:last-child > .table:last-child {
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
+ border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
+ border-bottom-right-radius: 3px;
+}
+.panel > .panel-body + .table,
+.panel > .panel-body + .table-responsive,
+.panel > .table + .panel-body,
+.panel > .table-responsive + .panel-body {
+ border-top: 1px solid #ddd;
+}
+.panel > .table > tbody:first-child > tr:first-child th,
+.panel > .table > tbody:first-child > tr:first-child td {
+ border-top: 0;
+}
+.panel > .table-bordered,
+.panel > .table-responsive > .table-bordered {
+ border: 0;
+}
+.panel > .table-bordered > thead > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
+.panel > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-bordered > thead > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
+.panel > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-bordered > tfoot > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+ border-left: 0;
+}
+.panel > .table-bordered > thead > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
+.panel > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-bordered > thead > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
+.panel > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-bordered > tfoot > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+ border-right: 0;
+}
+.panel > .table-bordered > thead > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
+.panel > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-bordered > thead > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
+.panel > .table-bordered > tbody > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
+ border-bottom: 0;
+}
+.panel > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-bordered > tfoot > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
+ border-bottom: 0;
+}
+.panel > .table-responsive {
+ margin-bottom: 0;
+ border: 0;
+}
+.panel-group {
+ margin-bottom: 20px;
+}
+.panel-group .panel {
+ margin-bottom: 0;
+ border-radius: 4px;
+}
+.panel-group .panel + .panel {
+ margin-top: 5px;
+}
+.panel-group .panel-heading {
+ border-bottom: 0;
+}
+.panel-group .panel-heading + .panel-collapse > .panel-body,
+.panel-group .panel-heading + .panel-collapse > .list-group {
+ border-top: 1px solid #ddd;
+}
+.panel-group .panel-footer {
+ border-top: 0;
+}
+.panel-group .panel-footer + .panel-collapse .panel-body {
+ border-bottom: 1px solid #ddd;
+}
+.panel-default {
+ border-color: #ddd;
+}
+.panel-default > .panel-heading {
+ color: #333;
+ background-color: #f5f5f5;
+ border-color: #ddd;
+}
+.panel-default > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #ddd;
+}
+.panel-default > .panel-heading .badge {
+ color: #f5f5f5;
+ background-color: #333;
+}
+.panel-default > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #ddd;
+}
+.panel-primary {
+ border-color: #337ab7;
+}
+.panel-primary > .panel-heading {
+ color: #fff;
+ background-color: #337ab7;
+ border-color: #337ab7;
+}
+.panel-primary > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #337ab7;
+}
+.panel-primary > .panel-heading .badge {
+ color: #337ab7;
+ background-color: #fff;
+}
+.panel-primary > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #337ab7;
+}
+.panel-success {
+ border-color: #d6e9c6;
+}
+.panel-success > .panel-heading {
+ color: #3c763d;
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+}
+.panel-success > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #d6e9c6;
+}
+.panel-success > .panel-heading .badge {
+ color: #dff0d8;
+ background-color: #3c763d;
+}
+.panel-success > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #d6e9c6;
+}
+.panel-info {
+ border-color: #bce8f1;
+}
+.panel-info > .panel-heading {
+ color: #31708f;
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+}
+.panel-info > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #bce8f1;
+}
+.panel-info > .panel-heading .badge {
+ color: #d9edf7;
+ background-color: #31708f;
+}
+.panel-info > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #bce8f1;
+}
+.panel-warning {
+ border-color: #faebcc;
+}
+.panel-warning > .panel-heading {
+ color: #8a6d3b;
+ background-color: #fcf8e3;
+ border-color: #faebcc;
+}
+.panel-warning > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #faebcc;
+}
+.panel-warning > .panel-heading .badge {
+ color: #fcf8e3;
+ background-color: #8a6d3b;
+}
+.panel-warning > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #faebcc;
+}
+.panel-danger {
+ border-color: #ebccd1;
+}
+.panel-danger > .panel-heading {
+ color: #a94442;
+ background-color: #f2dede;
+ border-color: #ebccd1;
+}
+.panel-danger > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #ebccd1;
+}
+.panel-danger > .panel-heading .badge {
+ color: #f2dede;
+ background-color: #a94442;
+}
+.panel-danger > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #ebccd1;
+}
+.embed-responsive {
+ position: relative;
+ display: block;
+ height: 0;
+ padding: 0;
+ overflow: hidden;
+}
+.embed-responsive .embed-responsive-item,
+.embed-responsive iframe,
+.embed-responsive embed,
+.embed-responsive object,
+.embed-responsive video {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border: 0;
+}
+.embed-responsive-16by9 {
+ padding-bottom: 56.25%;
+}
+.embed-responsive-4by3 {
+ padding-bottom: 75%;
+}
+.well {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 20px;
+ background-color: #f5f5f5;
+ border: 1px solid #e3e3e3;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
+}
+.well blockquote {
+ border-color: #ddd;
+ border-color: rgba(0, 0, 0, .15);
+}
+.well-lg {
+ padding: 24px;
+ border-radius: 6px;
+}
+.well-sm {
+ padding: 9px;
+ border-radius: 3px;
+}
+.close {
+ float: right;
+ font-size: 21px;
+ font-weight: bold;
+ line-height: 1;
+ color: #000;
+ text-shadow: 0 1px 0 #fff;
+ filter: alpha(opacity=20);
+ opacity: .2;
+}
+.close:hover,
+.close:focus {
+ color: #000;
+ text-decoration: none;
+ cursor: pointer;
+ filter: alpha(opacity=50);
+ opacity: .5;
+}
+button.close {
+ -webkit-appearance: none;
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+ border: 0;
+}
+.modal-open {
+ overflow: hidden;
+}
+.modal {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1050;
+ display: none;
+ overflow: hidden;
+ -webkit-overflow-scrolling: touch;
+ outline: 0;
+}
+.modal.fade .modal-dialog {
+ -webkit-transition: -webkit-transform .3s ease-out;
+ -o-transition: -o-transform .3s ease-out;
+ transition: transform .3s ease-out;
+ -webkit-transform: translate(0, -25%);
+ -ms-transform: translate(0, -25%);
+ -o-transform: translate(0, -25%);
+ transform: translate(0, -25%);
+}
+.modal.in .modal-dialog {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ -o-transform: translate(0, 0);
+ transform: translate(0, 0);
+}
+.modal-open .modal {
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.modal-dialog {
+ position: relative;
+ width: auto;
+ margin: 10px;
+}
+.modal-content {
+ position: relative;
+ background-color: #fff;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ border: 1px solid #999;
+ border: 1px solid rgba(0, 0, 0, .2);
+ border-radius: 6px;
+ outline: 0;
+ -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
+ box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
+}
+.modal-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1040;
+ background-color: #000;
+}
+.modal-backdrop.fade {
+ filter: alpha(opacity=0);
+ opacity: 0;
+}
+.modal-backdrop.in {
+ filter: alpha(opacity=50);
+ opacity: .5;
+}
+.modal-header {
+ min-height: 16.42857143px;
+ padding: 15px;
+ border-bottom: 1px solid #e5e5e5;
+}
+.modal-header .close {
+ margin-top: -2px;
+}
+.modal-title {
+ margin: 0;
+ line-height: 1.42857143;
+}
+.modal-body {
+ position: relative;
+ padding: 15px;
+}
+.modal-footer {
+ padding: 15px;
+ text-align: right;
+ border-top: 1px solid #e5e5e5;
+}
+.modal-footer .btn + .btn {
+ margin-bottom: 0;
+ margin-left: 5px;
+}
+.modal-footer .btn-group .btn + .btn {
+ margin-left: -1px;
+}
+.modal-footer .btn-block + .btn-block {
+ margin-left: 0;
+}
+.modal-scrollbar-measure {
+ position: absolute;
+ top: -9999px;
+ width: 50px;
+ height: 50px;
+ overflow: scroll;
+}
+@media (min-width: 768px) {
+ .modal-dialog {
+ width: 600px;
+ margin: 30px auto;
+ }
+ .modal-content {
+ -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
+ box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
+ }
+ .modal-sm {
+ width: 300px;
+ }
+}
+@media (min-width: 992px) {
+ .modal-lg {
+ width: 900px;
+ }
+}
+.tooltip {
+ position: absolute;
+ z-index: 1070;
+ display: block;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1.42857143;
+ text-align: left;
+ text-align: start;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ letter-spacing: normal;
+ word-break: normal;
+ word-spacing: normal;
+ word-wrap: normal;
+ white-space: normal;
+ filter: alpha(opacity=0);
+ opacity: 0;
+
+ line-break: auto;
+}
+.tooltip.in {
+ filter: alpha(opacity=90);
+ opacity: .9;
+}
+.tooltip.top {
+ padding: 5px 0;
+ margin-top: -3px;
+}
+.tooltip.right {
+ padding: 0 5px;
+ margin-left: 3px;
+}
+.tooltip.bottom {
+ padding: 5px 0;
+ margin-top: 3px;
+}
+.tooltip.left {
+ padding: 0 5px;
+ margin-left: -3px;
+}
+.tooltip-inner {
+ max-width: 200px;
+ padding: 3px 8px;
+ color: #fff;
+ text-align: center;
+ background-color: #000;
+ border-radius: 4px;
+}
+.tooltip-arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.tooltip.top .tooltip-arrow {
+ bottom: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.top-left .tooltip-arrow {
+ right: 5px;
+ bottom: 0;
+ margin-bottom: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.top-right .tooltip-arrow {
+ bottom: 0;
+ left: 5px;
+ margin-bottom: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.right .tooltip-arrow {
+ top: 50%;
+ left: 0;
+ margin-top: -5px;
+ border-width: 5px 5px 5px 0;
+ border-right-color: #000;
+}
+.tooltip.left .tooltip-arrow {
+ top: 50%;
+ right: 0;
+ margin-top: -5px;
+ border-width: 5px 0 5px 5px;
+ border-left-color: #000;
+}
+.tooltip.bottom .tooltip-arrow {
+ top: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.tooltip.bottom-left .tooltip-arrow {
+ top: 0;
+ right: 5px;
+ margin-top: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+ top: 0;
+ left: 5px;
+ margin-top: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1060;
+ display: none;
+ max-width: 276px;
+ padding: 1px;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1.42857143;
+ text-align: left;
+ text-align: start;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ letter-spacing: normal;
+ word-break: normal;
+ word-spacing: normal;
+ word-wrap: normal;
+ white-space: normal;
+ background-color: #fff;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, .2);
+ border-radius: 6px;
+ -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+
+ line-break: auto;
+}
+.popover.top {
+ margin-top: -10px;
+}
+.popover.right {
+ margin-left: 10px;
+}
+.popover.bottom {
+ margin-top: 10px;
+}
+.popover.left {
+ margin-left: -10px;
+}
+.popover-title {
+ padding: 8px 14px;
+ margin: 0;
+ font-size: 14px;
+ background-color: #f7f7f7;
+ border-bottom: 1px solid #ebebeb;
+ border-radius: 5px 5px 0 0;
+}
+.popover-content {
+ padding: 9px 14px;
+}
+.popover > .arrow,
+.popover > .arrow:after {
+ position: absolute;
+ display: block;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.popover > .arrow {
+ border-width: 11px;
+}
+.popover > .arrow:after {
+ content: "";
+ border-width: 10px;
+}
+.popover.top > .arrow {
+ bottom: -11px;
+ left: 50%;
+ margin-left: -11px;
+ border-top-color: #999;
+ border-top-color: rgba(0, 0, 0, .25);
+ border-bottom-width: 0;
+}
+.popover.top > .arrow:after {
+ bottom: 1px;
+ margin-left: -10px;
+ content: " ";
+ border-top-color: #fff;
+ border-bottom-width: 0;
+}
+.popover.right > .arrow {
+ top: 50%;
+ left: -11px;
+ margin-top: -11px;
+ border-right-color: #999;
+ border-right-color: rgba(0, 0, 0, .25);
+ border-left-width: 0;
+}
+.popover.right > .arrow:after {
+ bottom: -10px;
+ left: 1px;
+ content: " ";
+ border-right-color: #fff;
+ border-left-width: 0;
+}
+.popover.bottom > .arrow {
+ top: -11px;
+ left: 50%;
+ margin-left: -11px;
+ border-top-width: 0;
+ border-bottom-color: #999;
+ border-bottom-color: rgba(0, 0, 0, .25);
+}
+.popover.bottom > .arrow:after {
+ top: 1px;
+ margin-left: -10px;
+ content: " ";
+ border-top-width: 0;
+ border-bottom-color: #fff;
+}
+.popover.left > .arrow {
+ top: 50%;
+ right: -11px;
+ margin-top: -11px;
+ border-right-width: 0;
+ border-left-color: #999;
+ border-left-color: rgba(0, 0, 0, .25);
+}
+.popover.left > .arrow:after {
+ right: 1px;
+ bottom: -10px;
+ content: " ";
+ border-right-width: 0;
+ border-left-color: #fff;
+}
+.carousel {
+ position: relative;
+}
+.carousel-inner {
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+}
+.carousel-inner > .item {
+ position: relative;
+ display: none;
+ -webkit-transition: .6s ease-in-out left;
+ -o-transition: .6s ease-in-out left;
+ transition: .6s ease-in-out left;
+}
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+ line-height: 1;
+}
+@media all and (transform-3d), (-webkit-transform-3d) {
+ .carousel-inner > .item {
+ -webkit-transition: -webkit-transform .6s ease-in-out;
+ -o-transition: -o-transform .6s ease-in-out;
+ transition: transform .6s ease-in-out;
+
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ -webkit-perspective: 1000px;
+ perspective: 1000px;
+ }
+ .carousel-inner > .item.next,
+ .carousel-inner > .item.active.right {
+ left: 0;
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ }
+ .carousel-inner > .item.prev,
+ .carousel-inner > .item.active.left {
+ left: 0;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ }
+ .carousel-inner > .item.next.left,
+ .carousel-inner > .item.prev.right,
+ .carousel-inner > .item.active {
+ left: 0;
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+}
+.carousel-inner > .active,
+.carousel-inner > .next,
+.carousel-inner > .prev {
+ display: block;
+}
+.carousel-inner > .active {
+ left: 0;
+}
+.carousel-inner > .next,
+.carousel-inner > .prev {
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+.carousel-inner > .next {
+ left: 100%;
+}
+.carousel-inner > .prev {
+ left: -100%;
+}
+.carousel-inner > .next.left,
+.carousel-inner > .prev.right {
+ left: 0;
+}
+.carousel-inner > .active.left {
+ left: -100%;
+}
+.carousel-inner > .active.right {
+ left: 100%;
+}
+.carousel-control {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 15%;
+ font-size: 20px;
+ color: #fff;
+ text-align: center;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
+ filter: alpha(opacity=50);
+ opacity: .5;
+}
+.carousel-control.left {
+ background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+ background-image: -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+ background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));
+ background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
+ background-repeat: repeat-x;
+}
+.carousel-control.right {
+ right: 0;
+ left: auto;
+ background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+ background-image: -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+ background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));
+ background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
+ background-repeat: repeat-x;
+}
+.carousel-control:hover,
+.carousel-control:focus {
+ color: #fff;
+ text-decoration: none;
+ filter: alpha(opacity=90);
+ outline: 0;
+ opacity: .9;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-left,
+.carousel-control .glyphicon-chevron-right {
+ position: absolute;
+ top: 50%;
+ z-index: 5;
+ display: inline-block;
+ margin-top: -10px;
+}
+.carousel-control .icon-prev,
+.carousel-control .glyphicon-chevron-left {
+ left: 50%;
+ margin-left: -10px;
+}
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-right {
+ right: 50%;
+ margin-right: -10px;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next {
+ width: 20px;
+ height: 20px;
+ font-family: serif;
+ line-height: 1;
+}
+.carousel-control .icon-prev:before {
+ content: '\2039';
+}
+.carousel-control .icon-next:before {
+ content: '\203a';
+}
+.carousel-indicators {
+ position: absolute;
+ bottom: 10px;
+ left: 50%;
+ z-index: 15;
+ width: 60%;
+ padding-left: 0;
+ margin-left: -30%;
+ text-align: center;
+ list-style: none;
+}
+.carousel-indicators li {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ margin: 1px;
+ text-indent: -999px;
+ cursor: pointer;
+ background-color: #000 \9;
+ background-color: rgba(0, 0, 0, 0);
+ border: 1px solid #fff;
+ border-radius: 10px;
+}
+.carousel-indicators .active {
+ width: 12px;
+ height: 12px;
+ margin: 0;
+ background-color: #fff;
+}
+.carousel-caption {
+ position: absolute;
+ right: 15%;
+ bottom: 20px;
+ left: 15%;
+ z-index: 10;
+ padding-top: 20px;
+ padding-bottom: 20px;
+ color: #fff;
+ text-align: center;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
+}
+.carousel-caption .btn {
+ text-shadow: none;
+}
+@media screen and (min-width: 768px) {
+ .carousel-control .glyphicon-chevron-left,
+ .carousel-control .glyphicon-chevron-right,
+ .carousel-control .icon-prev,
+ .carousel-control .icon-next {
+ width: 30px;
+ height: 30px;
+ margin-top: -15px;
+ font-size: 30px;
+ }
+ .carousel-control .glyphicon-chevron-left,
+ .carousel-control .icon-prev {
+ margin-left: -15px;
+ }
+ .carousel-control .glyphicon-chevron-right,
+ .carousel-control .icon-next {
+ margin-right: -15px;
+ }
+ .carousel-caption {
+ right: 20%;
+ left: 20%;
+ padding-bottom: 30px;
+ }
+ .carousel-indicators {
+ bottom: 20px;
+ }
+}
+.clearfix:before,
+.clearfix:after,
+.dl-horizontal dd:before,
+.dl-horizontal dd:after,
+.container:before,
+.container:after,
+.container-fluid:before,
+.container-fluid:after,
+.row:before,
+.row:after,
+.form-horizontal .form-group:before,
+.form-horizontal .form-group:after,
+.btn-toolbar:before,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:before,
+.btn-group-vertical > .btn-group:after,
+.nav:before,
+.nav:after,
+.navbar:before,
+.navbar:after,
+.navbar-header:before,
+.navbar-header:after,
+.navbar-collapse:before,
+.navbar-collapse:after,
+.pager:before,
+.pager:after,
+.panel-body:before,
+.panel-body:after,
+.modal-footer:before,
+.modal-footer:after {
+ display: table;
+ content: " ";
+}
+.clearfix:after,
+.dl-horizontal dd:after,
+.container:after,
+.container-fluid:after,
+.row:after,
+.form-horizontal .form-group:after,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:after,
+.nav:after,
+.navbar:after,
+.navbar-header:after,
+.navbar-collapse:after,
+.pager:after,
+.panel-body:after,
+.modal-footer:after {
+ clear: both;
+}
+.center-block {
+ display: block;
+ margin-right: auto;
+ margin-left: auto;
+}
+.pull-right {
+ float: right !important;
+}
+.pull-left {
+ float: left !important;
+}
+.hide {
+ display: none !important;
+}
+.show {
+ display: block !important;
+}
+.invisible {
+ visibility: hidden;
+}
+.text-hide {
+ font: 0/0 a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+}
+.hidden {
+ display: none !important;
+}
+.affix {
+ position: fixed;
+}
+@-ms-viewport {
+ width: device-width;
+}
+.visible-xs,
+.visible-sm,
+.visible-md,
+.visible-lg {
+ display: none !important;
+}
+.visible-xs-block,
+.visible-xs-inline,
+.visible-xs-inline-block,
+.visible-sm-block,
+.visible-sm-inline,
+.visible-sm-inline-block,
+.visible-md-block,
+.visible-md-inline,
+.visible-md-inline-block,
+.visible-lg-block,
+.visible-lg-inline,
+.visible-lg-inline-block {
+ display: none !important;
+}
+@media (max-width: 767px) {
+ .visible-xs {
+ display: block !important;
+ }
+ table.visible-xs {
+ display: table !important;
+ }
+ tr.visible-xs {
+ display: table-row !important;
+ }
+ th.visible-xs,
+ td.visible-xs {
+ display: table-cell !important;
+ }
+}
+@media (max-width: 767px) {
+ .visible-xs-block {
+ display: block !important;
+ }
+}
+@media (max-width: 767px) {
+ .visible-xs-inline {
+ display: inline !important;
+ }
+}
+@media (max-width: 767px) {
+ .visible-xs-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm {
+ display: block !important;
+ }
+ table.visible-sm {
+ display: table !important;
+ }
+ tr.visible-sm {
+ display: table-row !important;
+ }
+ th.visible-sm,
+ td.visible-sm {
+ display: table-cell !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm-block {
+ display: block !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm-inline {
+ display: inline !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .visible-sm-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md {
+ display: block !important;
+ }
+ table.visible-md {
+ display: table !important;
+ }
+ tr.visible-md {
+ display: table-row !important;
+ }
+ th.visible-md,
+ td.visible-md {
+ display: table-cell !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md-block {
+ display: block !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md-inline {
+ display: inline !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .visible-md-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg {
+ display: block !important;
+ }
+ table.visible-lg {
+ display: table !important;
+ }
+ tr.visible-lg {
+ display: table-row !important;
+ }
+ th.visible-lg,
+ td.visible-lg {
+ display: table-cell !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg-block {
+ display: block !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg-inline {
+ display: inline !important;
+ }
+}
+@media (min-width: 1200px) {
+ .visible-lg-inline-block {
+ display: inline-block !important;
+ }
+}
+@media (max-width: 767px) {
+ .hidden-xs {
+ display: none !important;
+ }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .hidden-sm {
+ display: none !important;
+ }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+ .hidden-md {
+ display: none !important;
+ }
+}
+@media (min-width: 1200px) {
+ .hidden-lg {
+ display: none !important;
+ }
+}
+.visible-print {
+ display: none !important;
+}
+@media print {
+ .visible-print {
+ display: block !important;
+ }
+ table.visible-print {
+ display: table !important;
+ }
+ tr.visible-print {
+ display: table-row !important;
+ }
+ th.visible-print,
+ td.visible-print {
+ display: table-cell !important;
+ }
+}
+.visible-print-block {
+ display: none !important;
+}
+@media print {
+ .visible-print-block {
+ display: block !important;
+ }
+}
+.visible-print-inline {
+ display: none !important;
+}
+@media print {
+ .visible-print-inline {
+ display: inline !important;
+ }
+}
+.visible-print-inline-block {
+ display: none !important;
+}
+@media print {
+ .visible-print-inline-block {
+ display: inline-block !important;
+ }
+}
+@media print {
+ .hidden-print {
+ display: none !important;
+ }
+}
+/*# sourceMappingURL=bootstrap.css.map */
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap.css.map b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap.css.map
new file mode 100644
index 00000000..9f60ed2b
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["bootstrap.css","less/normalize.less","less/print.less","less/glyphicons.less","less/scaffolding.less","less/mixins/vendor-prefixes.less","less/mixins/tab-focus.less","less/mixins/image.less","less/type.less","less/mixins/text-emphasis.less","less/mixins/background-variant.less","less/mixins/text-overflow.less","less/code.less","less/grid.less","less/mixins/grid.less","less/mixins/grid-framework.less","less/tables.less","less/mixins/table-row.less","less/forms.less","less/mixins/forms.less","less/buttons.less","less/mixins/buttons.less","less/mixins/opacity.less","less/component-animations.less","less/dropdowns.less","less/mixins/nav-divider.less","less/mixins/reset-filter.less","less/button-groups.less","less/mixins/border-radius.less","less/input-groups.less","less/navs.less","less/navbar.less","less/mixins/nav-vertical-align.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/mixins/pagination.less","less/pager.less","less/labels.less","less/mixins/labels.less","less/badges.less","less/jumbotron.less","less/thumbnails.less","less/alerts.less","less/mixins/alerts.less","less/progress-bars.less","less/mixins/gradients.less","less/mixins/progress-bar.less","less/media.less","less/list-group.less","less/mixins/list-group.less","less/panels.less","less/mixins/panels.less","less/responsive-embed.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/mixins/reset-text.less","less/popovers.less","less/carousel.less","less/mixins/clearfix.less","less/mixins/center-block.less","less/mixins/hide-text.less","less/responsive-utilities.less","less/mixins/responsive-visibility.less"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,4EAA4E;ACG5E;EACE,wBAAA;EACA,2BAAA;EACA,+BAAA;CDDD;ACQD;EACE,UAAA;CDND;ACmBD;;;;;;;;;;;;;EAaE,eAAA;CDjBD;ACyBD;;;;EAIE,sBAAA;EACA,yBAAA;CDvBD;AC+BD;EACE,cAAA;EACA,UAAA;CD7BD;ACqCD;;EAEE,cAAA;CDnCD;AC6CD;EACE,8BAAA;CD3CD;ACmDD;;EAEE,WAAA;CDjDD;AC2DD;EACE,0BAAA;CDzDD;ACgED;;EAEE,kBAAA;CD9DD;ACqED;EACE,mBAAA;CDnED;AC2ED;EACE,eAAA;EACA,iBAAA;CDzED;ACgFD;EACE,iBAAA;EACA,YAAA;CD9ED;ACqFD;EACE,eAAA;CDnFD;AC0FD;;EAEE,eAAA;EACA,eAAA;EACA,mBAAA;EACA,yBAAA;CDxFD;AC2FD;EACE,YAAA;CDzFD;AC4FD;EACE,gBAAA;CD1FD;ACoGD;EACE,UAAA;CDlGD;ACyGD;EACE,iBAAA;CDvGD;ACiHD;EACE,iBAAA;CD/GD;ACsHD;EACE,gCAAA;KAAA,6BAAA;UAAA,wBAAA;EACA,UAAA;CDpHD;AC2HD;EACE,eAAA;CDzHD;ACgID;;;;EAIE,kCAAA;EACA,eAAA;CD9HD;ACgJD;;;;;EAKE,eAAA;EACA,cAAA;EACA,UAAA;CD9ID;ACqJD;EACE,kBAAA;CDnJD;AC6JD;;EAEE,qBAAA;CD3JD;ACsKD;;;;EAIE,2BAAA;EACA,gBAAA;CDpKD;AC2KD;;EAEE,gBAAA;CDzKD;ACgLD;;EAEE,UAAA;EACA,WAAA;CD9KD;ACsLD;EACE,oBAAA;CDpLD;AC+LD;;EAEE,+BAAA;KAAA,4BAAA;UAAA,uBAAA;EACA,WAAA;CD7LD;ACsMD;;EAEE,aAAA;CDpMD;AC4MD;EACE,8BAAA;EACA,gCAAA;KAAA,6BAAA;UAAA,wBAAA;CD1MD;ACmND;;EAEE,yBAAA;CDjND;ACwND;EACE,0BAAA;EACA,cAAA;EACA,+BAAA;CDtND;AC8ND;EACE,UAAA;EACA,WAAA;CD5ND;ACmOD;EACE,eAAA;CDjOD;ACyOD;EACE,kBAAA;CDvOD;ACiPD;EACE,0BAAA;EACA,kBAAA;CD/OD;ACkPD;;EAEE,WAAA;CDhPD;AACD,qFAAqF;AElFrF;EA7FI;;;IAGI,mCAAA;IACA,uBAAA;IACA,oCAAA;YAAA,4BAAA;IACA,6BAAA;GFkLL;EE/KC;;IAEI,2BAAA;GFiLL;EE9KC;IACI,6BAAA;GFgLL;EE7KC;IACI,8BAAA;GF+KL;EE1KC;;IAEI,YAAA;GF4KL;EEzKC;;IAEI,uBAAA;IACA,yBAAA;GF2KL;EExKC;IACI,4BAAA;GF0KL;EEvKC;;IAEI,yBAAA;GFyKL;EEtKC;IACI,2BAAA;GFwKL;EErKC;;;IAGI,WAAA;IACA,UAAA;GFuKL;EEpKC;;IAEI,wBAAA;GFsKL;EEhKC;IACI,cAAA;GFkKL;EEhKC;;IAGQ,kCAAA;GFiKT;EE9JC;IACI,uBAAA;GFgKL;EE7JC;IACI,qCAAA;GF+JL;EEhKC;;IAKQ,kCAAA;GF+JT;EE5JC;;IAGQ,kCAAA;GF6JT;CACF;AGnPD;EACE,oCAAA;EACA,sDAAA;EACA,gYAAA;CHqPD;AG7OD;EACE,mBAAA;EACA,SAAA;EACA,sBAAA;EACA,oCAAA;EACA,mBAAA;EACA,oBAAA;EACA,eAAA;EACA,oCAAA;EACA,mCAAA;CH+OD;AG3OmC;EAAW,eAAA;CH8O9C;AG7OmC;EAAW,eAAA;CHgP9C;AG9OmC;;EAAW,iBAAA;CHkP9C;AGjPmC;EAAW,iBAAA;CHoP9C;AGnPmC;EAAW,iBAAA;CHsP9C;AGrPmC;EAAW,iBAAA;CHwP9C;AGvPmC;EAAW,iBAAA;CH0P9C;AGzPmC;EAAW,iBAAA;CH4P9C;AG3PmC;EAAW,iBAAA;CH8P9C;AG7PmC;EAAW,iBAAA;CHgQ9C;AG/PmC;EAAW,iBAAA;CHkQ9C;AGjQmC;EAAW,iBAAA;CHoQ9C;AGnQmC;EAAW,iBAAA;CHsQ9C;AGrQmC;EAAW,iBAAA;CHwQ9C;AGvQmC;EAAW,iBAAA;CH0Q9C;AGzQmC;EAAW,iBAAA;CH4Q9C;AG3QmC;EAAW,iBAAA;CH8Q9C;AG7QmC;EAAW,iBAAA;CHgR9C;AG/QmC;EAAW,iBAAA;CHkR9C;AGjRmC;EAAW,iBAAA;CHoR9C;AGnRmC;EAAW,iBAAA;CHsR9C;AGrRmC;EAAW,iBAAA;CHwR9C;AGvRmC;EAAW,iBAAA;CH0R9C;AGzRmC;EAAW,iBAAA;CH4R9C;AG3RmC;EAAW,iBAAA;CH8R9C;AG7RmC;EAAW,iBAAA;CHgS9C;AG/RmC;EAAW,iBAAA;CHkS9C;AGjSmC;EAAW,iBAAA;CHoS9C;AGnSmC;EAAW,iBAAA;CHsS9C;AGrSmC;EAAW,iBAAA;CHwS9C;AGvSmC;EAAW,iBAAA;CH0S9C;AGzSmC;EAAW,iBAAA;CH4S9C;AG3SmC;EAAW,iBAAA;CH8S9C;AG7SmC;EAAW,iBAAA;CHgT9C;AG/SmC;EAAW,iBAAA;CHkT9C;AGjTmC;EAAW,iBAAA;CHoT9C;AGnTmC;EAAW,iBAAA;CHsT9C;AGrTmC;EAAW,iBAAA;CHwT9C;AGvTmC;EAAW,iBAAA;CH0T9C;AGzTmC;EAAW,iBAAA;CH4T9C;AG3TmC;EAAW,iBAAA;CH8T9C;AG7TmC;EAAW,iBAAA;CHgU9C;AG/TmC;EAAW,iBAAA;CHkU9C;AGjUmC;EAAW,iBAAA;CHoU9C;AGnUmC;EAAW,iBAAA;CHsU9C;AGrUmC;EAAW,iBAAA;CHwU9C;AGvUmC;EAAW,iBAAA;CH0U9C;AGzUmC;EAAW,iBAAA;CH4U9C;AG3UmC;EAAW,iBAAA;CH8U9C;AG7UmC;EAAW,iBAAA;CHgV9C;AG/UmC;EAAW,iBAAA;CHkV9C;AGjVmC;EAAW,iBAAA;CHoV9C;AGnVmC;EAAW,iBAAA;CHsV9C;AGrVmC;EAAW,iBAAA;CHwV9C;AGvVmC;EAAW,iBAAA;CH0V9C;AGzVmC;EAAW,iBAAA;CH4V9C;AG3VmC;EAAW,iBAAA;CH8V9C;AG7VmC;EAAW,iBAAA;CHgW9C;AG/VmC;EAAW,iBAAA;CHkW9C;AGjWmC;EAAW,iBAAA;CHoW9C;AGnWmC;EAAW,iBAAA;CHsW9C;AGrWmC;EAAW,iBAAA;CHwW9C;AGvWmC;EAAW,iBAAA;CH0W9C;AGzWmC;EAAW,iBAAA;CH4W9C;AG3WmC;EAAW,iBAAA;CH8W9C;AG7WmC;EAAW,iBAAA;CHgX9C;AG/WmC;EAAW,iBAAA;CHkX9C;AGjXmC;EAAW,iBAAA;CHoX9C;AGnXmC;EAAW,iBAAA;CHsX9C;AGrXmC;EAAW,iBAAA;CHwX9C;AGvXmC;EAAW,iBAAA;CH0X9C;AGzXmC;EAAW,iBAAA;CH4X9C;AG3XmC;EAAW,iBAAA;CH8X9C;AG7XmC;EAAW,iBAAA;CHgY9C;AG/XmC;EAAW,iBAAA;CHkY9C;AGjYmC;EAAW,iBAAA;CHoY9C;AGnYmC;EAAW,iBAAA;CHsY9C;AGrYmC;EAAW,iBAAA;CHwY9C;AGvYmC;EAAW,iBAAA;CH0Y9C;AGzYmC;EAAW,iBAAA;CH4Y9C;AG3YmC;EAAW,iBAAA;CH8Y9C;AG7YmC;EAAW,iBAAA;CHgZ9C;AG/YmC;EAAW,iBAAA;CHkZ9C;AGjZmC;EAAW,iBAAA;CHoZ9C;AGnZmC;EAAW,iBAAA;CHsZ9C;AGrZmC;EAAW,iBAAA;CHwZ9C;AGvZmC;EAAW,iBAAA;CH0Z9C;AGzZmC;EAAW,iBAAA;CH4Z9C;AG3ZmC;EAAW,iBAAA;CH8Z9C;AG7ZmC;EAAW,iBAAA;CHga9C;AG/ZmC;EAAW,iBAAA;CHka9C;AGjamC;EAAW,iBAAA;CHoa9C;AGnamC;EAAW,iBAAA;CHsa9C;AGramC;EAAW,iBAAA;CHwa9C;AGvamC;EAAW,iBAAA;CH0a9C;AGzamC;EAAW,iBAAA;CH4a9C;AG3amC;EAAW,iBAAA;CH8a9C;AG7amC;EAAW,iBAAA;CHgb9C;AG/amC;EAAW,iBAAA;CHkb9C;AGjbmC;EAAW,iBAAA;CHob9C;AGnbmC;EAAW,iBAAA;CHsb9C;AGrbmC;EAAW,iBAAA;CHwb9C;AGvbmC;EAAW,iBAAA;CH0b9C;AGzbmC;EAAW,iBAAA;CH4b9C;AG3bmC;EAAW,iBAAA;CH8b9C;AG7bmC;EAAW,iBAAA;CHgc9C;AG/bmC;EAAW,iBAAA;CHkc9C;AGjcmC;EAAW,iBAAA;CHoc9C;AGncmC;EAAW,iBAAA;CHsc9C;AGrcmC;EAAW,iBAAA;CHwc9C;AGvcmC;EAAW,iBAAA;CH0c9C;AGzcmC;EAAW,iBAAA;CH4c9C;AG3cmC;EAAW,iBAAA;CH8c9C;AG7cmC;EAAW,iBAAA;CHgd9C;AG/cmC;EAAW,iBAAA;CHkd9C;AGjdmC;EAAW,iBAAA;CHod9C;AGndmC;EAAW,iBAAA;CHsd9C;AGrdmC;EAAW,iBAAA;CHwd9C;AGvdmC;EAAW,iBAAA;CH0d9C;AGzdmC;EAAW,iBAAA;CH4d9C;AG3dmC;EAAW,iBAAA;CH8d9C;AG7dmC;EAAW,iBAAA;CHge9C;AG/dmC;EAAW,iBAAA;CHke9C;AGjemC;EAAW,iBAAA;CHoe9C;AGnemC;EAAW,iBAAA;CHse9C;AGremC;EAAW,iBAAA;CHwe9C;AGvemC;EAAW,iBAAA;CH0e9C;AGzemC;EAAW,iBAAA;CH4e9C;AG3emC;EAAW,iBAAA;CH8e9C;AG7emC;EAAW,iBAAA;CHgf9C;AG/emC;EAAW,iBAAA;CHkf9C;AGjfmC;EAAW,iBAAA;CHof9C;AGnfmC;EAAW,iBAAA;CHsf9C;AGrfmC;EAAW,iBAAA;CHwf9C;AGvfmC;EAAW,iBAAA;CH0f9C;AGzfmC;EAAW,iBAAA;CH4f9C;AG3fmC;EAAW,iBAAA;CH8f9C;AG7fmC;EAAW,iBAAA;CHggB9C;AG/fmC;EAAW,iBAAA;CHkgB9C;AGjgBmC;EAAW,iBAAA;CHogB9C;AGngBmC;EAAW,iBAAA;CHsgB9C;AGrgBmC;EAAW,iBAAA;CHwgB9C;AGvgBmC;EAAW,iBAAA;CH0gB9C;AGzgBmC;EAAW,iBAAA;CH4gB9C;AG3gBmC;EAAW,iBAAA;CH8gB9C;AG7gBmC;EAAW,iBAAA;CHghB9C;AG/gBmC;EAAW,iBAAA;CHkhB9C;AGjhBmC;EAAW,iBAAA;CHohB9C;AGnhBmC;EAAW,iBAAA;CHshB9C;AGrhBmC;EAAW,iBAAA;CHwhB9C;AGvhBmC;EAAW,iBAAA;CH0hB9C;AGzhBmC;EAAW,iBAAA;CH4hB9C;AG3hBmC;EAAW,iBAAA;CH8hB9C;AG7hBmC;EAAW,iBAAA;CHgiB9C;AG/hBmC;EAAW,iBAAA;CHkiB9C;AGjiBmC;EAAW,iBAAA;CHoiB9C;AGniBmC;EAAW,iBAAA;CHsiB9C;AGriBmC;EAAW,iBAAA;CHwiB9C;AGviBmC;EAAW,iBAAA;CH0iB9C;AGziBmC;EAAW,iBAAA;CH4iB9C;AG3iBmC;EAAW,iBAAA;CH8iB9C;AG7iBmC;EAAW,iBAAA;CHgjB9C;AG/iBmC;EAAW,iBAAA;CHkjB9C;AGjjBmC;EAAW,iBAAA;CHojB9C;AGnjBmC;EAAW,iBAAA;CHsjB9C;AGrjBmC;EAAW,iBAAA;CHwjB9C;AGvjBmC;EAAW,iBAAA;CH0jB9C;AGzjBmC;EAAW,iBAAA;CH4jB9C;AG3jBmC;EAAW,iBAAA;CH8jB9C;AG7jBmC;EAAW,iBAAA;CHgkB9C;AG/jBmC;EAAW,iBAAA;CHkkB9C;AGjkBmC;EAAW,iBAAA;CHokB9C;AGnkBmC;EAAW,iBAAA;CHskB9C;AGrkBmC;EAAW,iBAAA;CHwkB9C;AGvkBmC;EAAW,iBAAA;CH0kB9C;AGzkBmC;EAAW,iBAAA;CH4kB9C;AG3kBmC;EAAW,iBAAA;CH8kB9C;AG7kBmC;EAAW,iBAAA;CHglB9C;AG/kBmC;EAAW,iBAAA;CHklB9C;AGjlBmC;EAAW,iBAAA;CHolB9C;AGnlBmC;EAAW,iBAAA;CHslB9C;AGrlBmC;EAAW,iBAAA;CHwlB9C;AGvlBmC;EAAW,iBAAA;CH0lB9C;AGzlBmC;EAAW,iBAAA;CH4lB9C;AG3lBmC;EAAW,iBAAA;CH8lB9C;AG7lBmC;EAAW,iBAAA;CHgmB9C;AG/lBmC;EAAW,iBAAA;CHkmB9C;AGjmBmC;EAAW,iBAAA;CHomB9C;AGnmBmC;EAAW,iBAAA;CHsmB9C;AGrmBmC;EAAW,iBAAA;CHwmB9C;AGvmBmC;EAAW,iBAAA;CH0mB9C;AGzmBmC;EAAW,iBAAA;CH4mB9C;AG3mBmC;EAAW,iBAAA;CH8mB9C;AG7mBmC;EAAW,iBAAA;CHgnB9C;AG/mBmC;EAAW,iBAAA;CHknB9C;AGjnBmC;EAAW,iBAAA;CHonB9C;AGnnBmC;EAAW,iBAAA;CHsnB9C;AGrnBmC;EAAW,iBAAA;CHwnB9C;AGvnBmC;EAAW,iBAAA;CH0nB9C;AGznBmC;EAAW,iBAAA;CH4nB9C;AG3nBmC;EAAW,iBAAA;CH8nB9C;AG7nBmC;EAAW,iBAAA;CHgoB9C;AG/nBmC;EAAW,iBAAA;CHkoB9C;AGjoBmC;EAAW,iBAAA;CHooB9C;AGnoBmC;EAAW,iBAAA;CHsoB9C;AGroBmC;EAAW,iBAAA;CHwoB9C;AG/nBmC;EAAW,iBAAA;CHkoB9C;AGjoBmC;EAAW,iBAAA;CHooB9C;AGnoBmC;EAAW,iBAAA;CHsoB9C;AGroBmC;EAAW,iBAAA;CHwoB9C;AGvoBmC;EAAW,iBAAA;CH0oB9C;AGzoBmC;EAAW,iBAAA;CH4oB9C;AG3oBmC;EAAW,iBAAA;CH8oB9C;AG7oBmC;EAAW,iBAAA;CHgpB9C;AG/oBmC;EAAW,iBAAA;CHkpB9C;AGjpBmC;EAAW,iBAAA;CHopB9C;AGnpBmC;EAAW,iBAAA;CHspB9C;AGrpBmC;EAAW,iBAAA;CHwpB9C;AGvpBmC;EAAW,iBAAA;CH0pB9C;AGzpBmC;EAAW,iBAAA;CH4pB9C;AG3pBmC;EAAW,iBAAA;CH8pB9C;AG7pBmC;EAAW,iBAAA;CHgqB9C;AG/pBmC;EAAW,iBAAA;CHkqB9C;AGjqBmC;EAAW,iBAAA;CHoqB9C;AGnqBmC;EAAW,iBAAA;CHsqB9C;AGrqBmC;EAAW,iBAAA;CHwqB9C;AGvqBmC;EAAW,iBAAA;CH0qB9C;AGzqBmC;EAAW,iBAAA;CH4qB9C;AG3qBmC;EAAW,iBAAA;CH8qB9C;AG7qBmC;EAAW,iBAAA;CHgrB9C;AG/qBmC;EAAW,iBAAA;CHkrB9C;AGjrBmC;EAAW,iBAAA;CHorB9C;AGnrBmC;EAAW,iBAAA;CHsrB9C;AGrrBmC;EAAW,iBAAA;CHwrB9C;AGvrBmC;EAAW,iBAAA;CH0rB9C;AGzrBmC;EAAW,iBAAA;CH4rB9C;AG3rBmC;EAAW,iBAAA;CH8rB9C;AG7rBmC;EAAW,iBAAA;CHgsB9C;AG/rBmC;EAAW,iBAAA;CHksB9C;AGjsBmC;EAAW,iBAAA;CHosB9C;AGnsBmC;EAAW,iBAAA;CHssB9C;AGrsBmC;EAAW,iBAAA;CHwsB9C;AGvsBmC;EAAW,iBAAA;CH0sB9C;AGzsBmC;EAAW,iBAAA;CH4sB9C;AG3sBmC;EAAW,iBAAA;CH8sB9C;AG7sBmC;EAAW,iBAAA;CHgtB9C;AG/sBmC;EAAW,iBAAA;CHktB9C;AGjtBmC;EAAW,iBAAA;CHotB9C;AGntBmC;EAAW,iBAAA;CHstB9C;AGrtBmC;EAAW,iBAAA;CHwtB9C;AGvtBmC;EAAW,iBAAA;CH0tB9C;AGztBmC;EAAW,iBAAA;CH4tB9C;AG3tBmC;EAAW,iBAAA;CH8tB9C;AG7tBmC;EAAW,iBAAA;CHguB9C;AG/tBmC;EAAW,iBAAA;CHkuB9C;AGjuBmC;EAAW,iBAAA;CHouB9C;AGnuBmC;EAAW,iBAAA;CHsuB9C;AGruBmC;EAAW,iBAAA;CHwuB9C;AGvuBmC;EAAW,iBAAA;CH0uB9C;AGzuBmC;EAAW,iBAAA;CH4uB9C;AG3uBmC;EAAW,iBAAA;CH8uB9C;AG7uBmC;EAAW,iBAAA;CHgvB9C;AIthCD;ECgEE,+BAAA;EACG,4BAAA;EACK,uBAAA;CLy9BT;AIxhCD;;EC6DE,+BAAA;EACG,4BAAA;EACK,uBAAA;CL+9BT;AIthCD;EACE,gBAAA;EACA,8CAAA;CJwhCD;AIrhCD;EACE,4DAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,0BAAA;CJuhCD;AInhCD;;;;EAIE,qBAAA;EACA,mBAAA;EACA,qBAAA;CJqhCD;AI/gCD;EACE,eAAA;EACA,sBAAA;CJihCD;AI/gCC;;EAEE,eAAA;EACA,2BAAA;CJihCH;AI9gCC;EErDA,qBAAA;EAEA,2CAAA;EACA,qBAAA;CNqkCD;AIxgCD;EACE,UAAA;CJ0gCD;AIpgCD;EACE,uBAAA;CJsgCD;AIlgCD;;;;;EGvEE,eAAA;EACA,gBAAA;EACA,aAAA;CPglCD;AItgCD;EACE,mBAAA;CJwgCD;AIlgCD;EACE,aAAA;EACA,wBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;EC6FA,yCAAA;EACK,oCAAA;EACG,iCAAA;EEvLR,sBAAA;EACA,gBAAA;EACA,aAAA;CPgmCD;AIlgCD;EACE,mBAAA;CJogCD;AI9/BD;EACE,iBAAA;EACA,oBAAA;EACA,UAAA;EACA,8BAAA;CJggCD;AIx/BD;EACE,mBAAA;EACA,WAAA;EACA,YAAA;EACA,aAAA;EACA,WAAA;EACA,iBAAA;EACA,uBAAA;EACA,UAAA;CJ0/BD;AIl/BC;;EAEE,iBAAA;EACA,YAAA;EACA,aAAA;EACA,UAAA;EACA,kBAAA;EACA,WAAA;CJo/BH;AIz+BD;EACE,gBAAA;CJ2+BD;AQloCD;;;;;;;;;;;;EAEE,qBAAA;EACA,iBAAA;EACA,iBAAA;EACA,eAAA;CR8oCD;AQnpCD;;;;;;;;;;;;;;;;;;;;;;;;EASI,oBAAA;EACA,eAAA;EACA,eAAA;CRoqCH;AQhqCD;;;;;;EAGE,iBAAA;EACA,oBAAA;CRqqCD;AQzqCD;;;;;;;;;;;;EAQI,eAAA;CR+qCH;AQ5qCD;;;;;;EAGE,iBAAA;EACA,oBAAA;CRirCD;AQrrCD;;;;;;;;;;;;EAQI,eAAA;CR2rCH;AQvrCD;;EAAU,gBAAA;CR2rCT;AQ1rCD;;EAAU,gBAAA;CR8rCT;AQ7rCD;;EAAU,gBAAA;CRisCT;AQhsCD;;EAAU,gBAAA;CRosCT;AQnsCD;;EAAU,gBAAA;CRusCT;AQtsCD;;EAAU,gBAAA;CR0sCT;AQpsCD;EACE,iBAAA;CRssCD;AQnsCD;EACE,oBAAA;EACA,gBAAA;EACA,iBAAA;EACA,iBAAA;CRqsCD;AQhsCD;EAAA;IAFI,gBAAA;GRssCD;CACF;AQ9rCD;;EAEE,eAAA;CRgsCD;AQ7rCD;;EAEE,0BAAA;EACA,cAAA;CR+rCD;AQ3rCD;EAAuB,iBAAA;CR8rCtB;AQ7rCD;EAAuB,kBAAA;CRgsCtB;AQ/rCD;EAAuB,mBAAA;CRksCtB;AQjsCD;EAAuB,oBAAA;CRosCtB;AQnsCD;EAAuB,oBAAA;CRssCtB;AQnsCD;EAAuB,0BAAA;CRssCtB;AQrsCD;EAAuB,0BAAA;CRwsCtB;AQvsCD;EAAuB,2BAAA;CR0sCtB;AQvsCD;EACE,eAAA;CRysCD;AQvsCD;ECrGE,eAAA;CT+yCD;AS9yCC;;EAEE,eAAA;CTgzCH;AQ3sCD;ECxGE,eAAA;CTszCD;ASrzCC;;EAEE,eAAA;CTuzCH;AQ/sCD;EC3GE,eAAA;CT6zCD;AS5zCC;;EAEE,eAAA;CT8zCH;AQntCD;EC9GE,eAAA;CTo0CD;ASn0CC;;EAEE,eAAA;CTq0CH;AQvtCD;ECjHE,eAAA;CT20CD;AS10CC;;EAEE,eAAA;CT40CH;AQvtCD;EAGE,YAAA;EE3HA,0BAAA;CVm1CD;AUl1CC;;EAEE,0BAAA;CVo1CH;AQztCD;EE9HE,0BAAA;CV01CD;AUz1CC;;EAEE,0BAAA;CV21CH;AQ7tCD;EEjIE,0BAAA;CVi2CD;AUh2CC;;EAEE,0BAAA;CVk2CH;AQjuCD;EEpIE,0BAAA;CVw2CD;AUv2CC;;EAEE,0BAAA;CVy2CH;AQruCD;EEvIE,0BAAA;CV+2CD;AU92CC;;EAEE,0BAAA;CVg3CH;AQpuCD;EACE,oBAAA;EACA,oBAAA;EACA,iCAAA;CRsuCD;AQ9tCD;;EAEE,cAAA;EACA,oBAAA;CRguCD;AQnuCD;;;;EAMI,iBAAA;CRmuCH;AQ5tCD;EACE,gBAAA;EACA,iBAAA;CR8tCD;AQ1tCD;EALE,gBAAA;EACA,iBAAA;EAMA,kBAAA;CR6tCD;AQ/tCD;EAKI,sBAAA;EACA,kBAAA;EACA,mBAAA;CR6tCH;AQxtCD;EACE,cAAA;EACA,oBAAA;CR0tCD;AQxtCD;;EAEE,wBAAA;CR0tCD;AQxtCD;EACE,kBAAA;CR0tCD;AQxtCD;EACE,eAAA;CR0tCD;AQjsCD;EAAA;IAVM,YAAA;IACA,aAAA;IACA,YAAA;IACA,kBAAA;IGtNJ,iBAAA;IACA,wBAAA;IACA,oBAAA;GXs6CC;EQ3sCH;IAHM,mBAAA;GRitCH;CACF;AQxsCD;;EAGE,aAAA;EACA,kCAAA;CRysCD;AQvsCD;EACE,eAAA;EA9IqB,0BAAA;CRw1CtB;AQrsCD;EACE,mBAAA;EACA,iBAAA;EACA,kBAAA;EACA,+BAAA;CRusCD;AQlsCG;;;EACE,iBAAA;CRssCL;AQhtCD;;;EAmBI,eAAA;EACA,eAAA;EACA,wBAAA;EACA,eAAA;CRksCH;AQhsCG;;;EACE,uBAAA;CRosCL;AQ5rCD;;EAEE,oBAAA;EACA,gBAAA;EACA,gCAAA;EACA,eAAA;EACA,kBAAA;CR8rCD;AQxrCG;;;;;;EAAW,YAAA;CRgsCd;AQ/rCG;;;;;;EACE,uBAAA;CRssCL;AQhsCD;EACE,oBAAA;EACA,mBAAA;EACA,wBAAA;CRksCD;AYx+CD;;;;EAIE,+DAAA;CZ0+CD;AYt+CD;EACE,iBAAA;EACA,eAAA;EACA,eAAA;EACA,0BAAA;EACA,mBAAA;CZw+CD;AYp+CD;EACE,iBAAA;EACA,eAAA;EACA,eAAA;EACA,0BAAA;EACA,mBAAA;EACA,uDAAA;UAAA,+CAAA;CZs+CD;AY5+CD;EASI,WAAA;EACA,gBAAA;EACA,kBAAA;EACA,yBAAA;UAAA,iBAAA;CZs+CH;AYj+CD;EACE,eAAA;EACA,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,wBAAA;EACA,sBAAA;EACA,sBAAA;EACA,eAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;CZm+CD;AY9+CD;EAeI,WAAA;EACA,mBAAA;EACA,eAAA;EACA,sBAAA;EACA,8BAAA;EACA,iBAAA;CZk+CH;AY79CD;EACE,kBAAA;EACA,mBAAA;CZ+9CD;AazhDD;ECHE,mBAAA;EACA,kBAAA;EACA,mBAAA;EACA,oBAAA;Cd+hDD;AazhDC;EAAA;IAFE,aAAA;Gb+hDD;CACF;Aa3hDC;EAAA;IAFE,aAAA;GbiiDD;CACF;Aa7hDD;EAAA;IAFI,cAAA;GbmiDD;CACF;Aa1hDD;ECvBE,mBAAA;EACA,kBAAA;EACA,mBAAA;EACA,oBAAA;CdojDD;AavhDD;ECvBE,mBAAA;EACA,oBAAA;CdijDD;AejjDG;EACE,mBAAA;EAEA,gBAAA;EAEA,mBAAA;EACA,oBAAA;CfijDL;AejiDG;EACE,YAAA;CfmiDL;Ae5hDC;EACE,YAAA;Cf8hDH;Ae/hDC;EACE,oBAAA;CfiiDH;AeliDC;EACE,oBAAA;CfoiDH;AeriDC;EACE,WAAA;CfuiDH;AexiDC;EACE,oBAAA;Cf0iDH;Ae3iDC;EACE,oBAAA;Cf6iDH;Ae9iDC;EACE,WAAA;CfgjDH;AejjDC;EACE,oBAAA;CfmjDH;AepjDC;EACE,oBAAA;CfsjDH;AevjDC;EACE,WAAA;CfyjDH;Ae1jDC;EACE,oBAAA;Cf4jDH;Ae7jDC;EACE,mBAAA;Cf+jDH;AejjDC;EACE,YAAA;CfmjDH;AepjDC;EACE,oBAAA;CfsjDH;AevjDC;EACE,oBAAA;CfyjDH;Ae1jDC;EACE,WAAA;Cf4jDH;Ae7jDC;EACE,oBAAA;Cf+jDH;AehkDC;EACE,oBAAA;CfkkDH;AenkDC;EACE,WAAA;CfqkDH;AetkDC;EACE,oBAAA;CfwkDH;AezkDC;EACE,oBAAA;Cf2kDH;Ae5kDC;EACE,WAAA;Cf8kDH;Ae/kDC;EACE,oBAAA;CfilDH;AellDC;EACE,mBAAA;CfolDH;AehlDC;EACE,YAAA;CfklDH;AelmDC;EACE,WAAA;CfomDH;AermDC;EACE,mBAAA;CfumDH;AexmDC;EACE,mBAAA;Cf0mDH;Ae3mDC;EACE,UAAA;Cf6mDH;Ae9mDC;EACE,mBAAA;CfgnDH;AejnDC;EACE,mBAAA;CfmnDH;AepnDC;EACE,UAAA;CfsnDH;AevnDC;EACE,mBAAA;CfynDH;Ae1nDC;EACE,mBAAA;Cf4nDH;Ae7nDC;EACE,UAAA;Cf+nDH;AehoDC;EACE,mBAAA;CfkoDH;AenoDC;EACE,kBAAA;CfqoDH;AejoDC;EACE,WAAA;CfmoDH;AernDC;EACE,kBAAA;CfunDH;AexnDC;EACE,0BAAA;Cf0nDH;Ae3nDC;EACE,0BAAA;Cf6nDH;Ae9nDC;EACE,iBAAA;CfgoDH;AejoDC;EACE,0BAAA;CfmoDH;AepoDC;EACE,0BAAA;CfsoDH;AevoDC;EACE,iBAAA;CfyoDH;Ae1oDC;EACE,0BAAA;Cf4oDH;Ae7oDC;EACE,0BAAA;Cf+oDH;AehpDC;EACE,iBAAA;CfkpDH;AenpDC;EACE,0BAAA;CfqpDH;AetpDC;EACE,yBAAA;CfwpDH;AezpDC;EACE,gBAAA;Cf2pDH;Aa3pDD;EElCI;IACE,YAAA;GfgsDH;EezrDD;IACE,YAAA;Gf2rDD;Ee5rDD;IACE,oBAAA;Gf8rDD;Ee/rDD;IACE,oBAAA;GfisDD;EelsDD;IACE,WAAA;GfosDD;EersDD;IACE,oBAAA;GfusDD;EexsDD;IACE,oBAAA;Gf0sDD;Ee3sDD;IACE,WAAA;Gf6sDD;Ee9sDD;IACE,oBAAA;GfgtDD;EejtDD;IACE,oBAAA;GfmtDD;EeptDD;IACE,WAAA;GfstDD;EevtDD;IACE,oBAAA;GfytDD;Ee1tDD;IACE,mBAAA;Gf4tDD;Ee9sDD;IACE,YAAA;GfgtDD;EejtDD;IACE,oBAAA;GfmtDD;EeptDD;IACE,oBAAA;GfstDD;EevtDD;IACE,WAAA;GfytDD;Ee1tDD;IACE,oBAAA;Gf4tDD;Ee7tDD;IACE,oBAAA;Gf+tDD;EehuDD;IACE,WAAA;GfkuDD;EenuDD;IACE,oBAAA;GfquDD;EetuDD;IACE,oBAAA;GfwuDD;EezuDD;IACE,WAAA;Gf2uDD;Ee5uDD;IACE,oBAAA;Gf8uDD;Ee/uDD;IACE,mBAAA;GfivDD;Ee7uDD;IACE,YAAA;Gf+uDD;Ee/vDD;IACE,WAAA;GfiwDD;EelwDD;IACE,mBAAA;GfowDD;EerwDD;IACE,mBAAA;GfuwDD;EexwDD;IACE,UAAA;Gf0wDD;Ee3wDD;IACE,mBAAA;Gf6wDD;Ee9wDD;IACE,mBAAA;GfgxDD;EejxDD;IACE,UAAA;GfmxDD;EepxDD;IACE,mBAAA;GfsxDD;EevxDD;IACE,mBAAA;GfyxDD;Ee1xDD;IACE,UAAA;Gf4xDD;Ee7xDD;IACE,mBAAA;Gf+xDD;EehyDD;IACE,kBAAA;GfkyDD;Ee9xDD;IACE,WAAA;GfgyDD;EelxDD;IACE,kBAAA;GfoxDD;EerxDD;IACE,0BAAA;GfuxDD;EexxDD;IACE,0BAAA;Gf0xDD;Ee3xDD;IACE,iBAAA;Gf6xDD;Ee9xDD;IACE,0BAAA;GfgyDD;EejyDD;IACE,0BAAA;GfmyDD;EepyDD;IACE,iBAAA;GfsyDD;EevyDD;IACE,0BAAA;GfyyDD;Ee1yDD;IACE,0BAAA;Gf4yDD;Ee7yDD;IACE,iBAAA;Gf+yDD;EehzDD;IACE,0BAAA;GfkzDD;EenzDD;IACE,yBAAA;GfqzDD;EetzDD;IACE,gBAAA;GfwzDD;CACF;AahzDD;EE3CI;IACE,YAAA;Gf81DH;Eev1DD;IACE,YAAA;Gfy1DD;Ee11DD;IACE,oBAAA;Gf41DD;Ee71DD;IACE,oBAAA;Gf+1DD;Eeh2DD;IACE,WAAA;Gfk2DD;Een2DD;IACE,oBAAA;Gfq2DD;Eet2DD;IACE,oBAAA;Gfw2DD;Eez2DD;IACE,WAAA;Gf22DD;Ee52DD;IACE,oBAAA;Gf82DD;Ee/2DD;IACE,oBAAA;Gfi3DD;Eel3DD;IACE,WAAA;Gfo3DD;Eer3DD;IACE,oBAAA;Gfu3DD;Eex3DD;IACE,mBAAA;Gf03DD;Ee52DD;IACE,YAAA;Gf82DD;Ee/2DD;IACE,oBAAA;Gfi3DD;Eel3DD;IACE,oBAAA;Gfo3DD;Eer3DD;IACE,WAAA;Gfu3DD;Eex3DD;IACE,oBAAA;Gf03DD;Ee33DD;IACE,oBAAA;Gf63DD;Ee93DD;IACE,WAAA;Gfg4DD;Eej4DD;IACE,oBAAA;Gfm4DD;Eep4DD;IACE,oBAAA;Gfs4DD;Eev4DD;IACE,WAAA;Gfy4DD;Ee14DD;IACE,oBAAA;Gf44DD;Ee74DD;IACE,mBAAA;Gf+4DD;Ee34DD;IACE,YAAA;Gf64DD;Ee75DD;IACE,WAAA;Gf+5DD;Eeh6DD;IACE,mBAAA;Gfk6DD;Een6DD;IACE,mBAAA;Gfq6DD;Eet6DD;IACE,UAAA;Gfw6DD;Eez6DD;IACE,mBAAA;Gf26DD;Ee56DD;IACE,mBAAA;Gf86DD;Ee/6DD;IACE,UAAA;Gfi7DD;Eel7DD;IACE,mBAAA;Gfo7DD;Eer7DD;IACE,mBAAA;Gfu7DD;Eex7DD;IACE,UAAA;Gf07DD;Ee37DD;IACE,mBAAA;Gf67DD;Ee97DD;IACE,kBAAA;Gfg8DD;Ee57DD;IACE,WAAA;Gf87DD;Eeh7DD;IACE,kBAAA;Gfk7DD;Een7DD;IACE,0BAAA;Gfq7DD;Eet7DD;IACE,0BAAA;Gfw7DD;Eez7DD;IACE,iBAAA;Gf27DD;Ee57DD;IACE,0BAAA;Gf87DD;Ee/7DD;IACE,0BAAA;Gfi8DD;Eel8DD;IACE,iBAAA;Gfo8DD;Eer8DD;IACE,0BAAA;Gfu8DD;Eex8DD;IACE,0BAAA;Gf08DD;Ee38DD;IACE,iBAAA;Gf68DD;Ee98DD;IACE,0BAAA;Gfg9DD;Eej9DD;IACE,yBAAA;Gfm9DD;Eep9DD;IACE,gBAAA;Gfs9DD;CACF;Aa38DD;EE9CI;IACE,YAAA;Gf4/DH;Eer/DD;IACE,YAAA;Gfu/DD;Eex/DD;IACE,oBAAA;Gf0/DD;Ee3/DD;IACE,oBAAA;Gf6/DD;Ee9/DD;IACE,WAAA;GfggED;EejgED;IACE,oBAAA;GfmgED;EepgED;IACE,oBAAA;GfsgED;EevgED;IACE,WAAA;GfygED;Ee1gED;IACE,oBAAA;Gf4gED;Ee7gED;IACE,oBAAA;Gf+gED;EehhED;IACE,WAAA;GfkhED;EenhED;IACE,oBAAA;GfqhED;EethED;IACE,mBAAA;GfwhED;Ee1gED;IACE,YAAA;Gf4gED;Ee7gED;IACE,oBAAA;Gf+gED;EehhED;IACE,oBAAA;GfkhED;EenhED;IACE,WAAA;GfqhED;EethED;IACE,oBAAA;GfwhED;EezhED;IACE,oBAAA;Gf2hED;Ee5hED;IACE,WAAA;Gf8hED;Ee/hED;IACE,oBAAA;GfiiED;EeliED;IACE,oBAAA;GfoiED;EeriED;IACE,WAAA;GfuiED;EexiED;IACE,oBAAA;Gf0iED;Ee3iED;IACE,mBAAA;Gf6iED;EeziED;IACE,YAAA;Gf2iED;Ee3jED;IACE,WAAA;Gf6jED;Ee9jED;IACE,mBAAA;GfgkED;EejkED;IACE,mBAAA;GfmkED;EepkED;IACE,UAAA;GfskED;EevkED;IACE,mBAAA;GfykED;Ee1kED;IACE,mBAAA;Gf4kED;Ee7kED;IACE,UAAA;Gf+kED;EehlED;IACE,mBAAA;GfklED;EenlED;IACE,mBAAA;GfqlED;EetlED;IACE,UAAA;GfwlED;EezlED;IACE,mBAAA;Gf2lED;Ee5lED;IACE,kBAAA;Gf8lED;Ee1lED;IACE,WAAA;Gf4lED;Ee9kED;IACE,kBAAA;GfglED;EejlED;IACE,0BAAA;GfmlED;EeplED;IACE,0BAAA;GfslED;EevlED;IACE,iBAAA;GfylED;Ee1lED;IACE,0BAAA;Gf4lED;Ee7lED;IACE,0BAAA;Gf+lED;EehmED;IACE,iBAAA;GfkmED;EenmED;IACE,0BAAA;GfqmED;EetmED;IACE,0BAAA;GfwmED;EezmED;IACE,iBAAA;Gf2mED;Ee5mED;IACE,0BAAA;Gf8mED;Ee/mED;IACE,yBAAA;GfinED;EelnED;IACE,gBAAA;GfonED;CACF;AgBxrED;EACE,8BAAA;ChB0rED;AgBxrED;EACE,iBAAA;EACA,oBAAA;EACA,eAAA;EACA,iBAAA;ChB0rED;AgBxrED;EACE,iBAAA;ChB0rED;AgBprED;EACE,YAAA;EACA,gBAAA;EACA,oBAAA;ChBsrED;AgBzrED;;;;;;EAWQ,aAAA;EACA,wBAAA;EACA,oBAAA;EACA,8BAAA;ChBsrEP;AgBpsED;EAoBI,uBAAA;EACA,iCAAA;ChBmrEH;AgBxsED;;;;;;EA8BQ,cAAA;ChBkrEP;AgBhtED;EAoCI,8BAAA;ChB+qEH;AgBntED;EAyCI,0BAAA;ChB6qEH;AgBtqED;;;;;;EAOQ,aAAA;ChBuqEP;AgB5pED;EACE,0BAAA;ChB8pED;AgB/pED;;;;;;EAQQ,0BAAA;ChB+pEP;AgBvqED;;EAeM,yBAAA;ChB4pEL;AgBlpED;EAEI,0BAAA;ChBmpEH;AgB1oED;EAEI,0BAAA;ChB2oEH;AgBloED;EACE,iBAAA;EACA,YAAA;EACA,sBAAA;ChBooED;AgB/nEG;;EACE,iBAAA;EACA,YAAA;EACA,oBAAA;ChBkoEL;AiB9wEC;;;;;;;;;;;;EAOI,0BAAA;CjBqxEL;AiB/wEC;;;;;EAMI,0BAAA;CjBgxEL;AiBnyEC;;;;;;;;;;;;EAOI,0BAAA;CjB0yEL;AiBpyEC;;;;;EAMI,0BAAA;CjBqyEL;AiBxzEC;;;;;;;;;;;;EAOI,0BAAA;CjB+zEL;AiBzzEC;;;;;EAMI,0BAAA;CjB0zEL;AiB70EC;;;;;;;;;;;;EAOI,0BAAA;CjBo1EL;AiB90EC;;;;;EAMI,0BAAA;CjB+0EL;AiBl2EC;;;;;;;;;;;;EAOI,0BAAA;CjBy2EL;AiBn2EC;;;;;EAMI,0BAAA;CjBo2EL;AgBltED;EACE,iBAAA;EACA,kBAAA;ChBotED;AgBvpED;EAAA;IA1DI,YAAA;IACA,oBAAA;IACA,mBAAA;IACA,6CAAA;IACA,0BAAA;GhBqtED;EgB/pEH;IAlDM,iBAAA;GhBotEH;EgBlqEH;;;;;;IAzCY,oBAAA;GhBmtET;EgB1qEH;IAjCM,UAAA;GhB8sEH;EgB7qEH;;;;;;IAxBY,eAAA;GhB6sET;EgBrrEH;;;;;;IApBY,gBAAA;GhBitET;EgB7rEH;;;;IAPY,iBAAA;GhB0sET;CACF;AkBp6ED;EACE,WAAA;EACA,UAAA;EACA,UAAA;EAIA,aAAA;ClBm6ED;AkBh6ED;EACE,eAAA;EACA,YAAA;EACA,WAAA;EACA,oBAAA;EACA,gBAAA;EACA,qBAAA;EACA,eAAA;EACA,UAAA;EACA,iCAAA;ClBk6ED;AkB/5ED;EACE,sBAAA;EACA,gBAAA;EACA,mBAAA;EACA,kBAAA;ClBi6ED;AkBt5ED;Eb4BE,+BAAA;EACG,4BAAA;EACK,uBAAA;CL63ET;AkBt5ED;;EAEE,gBAAA;EACA,mBAAA;EACA,oBAAA;ClBw5ED;AkBr5ED;EACE,eAAA;ClBu5ED;AkBn5ED;EACE,eAAA;EACA,YAAA;ClBq5ED;AkBj5ED;;EAEE,aAAA;ClBm5ED;AkB/4ED;;;EZvEE,qBAAA;EAEA,2CAAA;EACA,qBAAA;CN09ED;AkB/4ED;EACE,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;ClBi5ED;AkBv3ED;EACE,eAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,0BAAA;EACA,uBAAA;EACA,0BAAA;EACA,mBAAA;EbxDA,yDAAA;EACQ,iDAAA;EAyHR,uFAAA;EACK,0EAAA;EACG,uEAAA;CL0zET;AmBl8EC;EACE,sBAAA;EACA,WAAA;EdUF,uFAAA;EACQ,+EAAA;CL27ET;AK15EC;EACE,eAAA;EACA,WAAA;CL45EH;AK15EC;EAA0B,eAAA;CL65E3B;AK55EC;EAAgC,eAAA;CL+5EjC;AkB/3EC;;;EAGE,0BAAA;EACA,WAAA;ClBi4EH;AkB93EC;;EAEE,oBAAA;ClBg4EH;AkB53EC;EACE,aAAA;ClB83EH;AkBl3ED;EACE,yBAAA;ClBo3ED;AkB50ED;EAtBI;;;;IACE,kBAAA;GlBw2EH;EkBr2EC;;;;;;;;IAEE,kBAAA;GlB62EH;EkB12EC;;;;;;;;IAEE,kBAAA;GlBk3EH;CACF;AkBx2ED;EACE,oBAAA;ClB02ED;AkBl2ED;;EAEE,mBAAA;EACA,eAAA;EACA,iBAAA;EACA,oBAAA;ClBo2ED;AkBz2ED;;EAQI,iBAAA;EACA,mBAAA;EACA,iBAAA;EACA,oBAAA;EACA,gBAAA;ClBq2EH;AkBl2ED;;;;EAIE,mBAAA;EACA,mBAAA;EACA,mBAAA;ClBo2ED;AkBj2ED;;EAEE,iBAAA;ClBm2ED;AkB/1ED;;EAEE,mBAAA;EACA,sBAAA;EACA,mBAAA;EACA,iBAAA;EACA,uBAAA;EACA,oBAAA;EACA,gBAAA;ClBi2ED;AkB/1ED;;EAEE,cAAA;EACA,kBAAA;ClBi2ED;AkBx1EC;;;;;;EAGE,oBAAA;ClB61EH;AkBv1EC;;;;EAEE,oBAAA;ClB21EH;AkBr1EC;;;;EAGI,oBAAA;ClBw1EL;AkB70ED;EAEE,iBAAA;EACA,oBAAA;EAEA,iBAAA;EACA,iBAAA;ClB60ED;AkB30EC;;EAEE,gBAAA;EACA,iBAAA;ClB60EH;AkBh0ED;EC7PE,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CnBgkFD;AmB9jFC;EACE,aAAA;EACA,kBAAA;CnBgkFH;AmB7jFC;;EAEE,aAAA;CnB+jFH;AkB50ED;EAEI,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;ClB60EH;AkBn1ED;EASI,aAAA;EACA,kBAAA;ClB60EH;AkBv1ED;;EAcI,aAAA;ClB60EH;AkB31ED;EAiBI,aAAA;EACA,iBAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;ClB60EH;AkBz0ED;ECzRE,aAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;CnBqmFD;AmBnmFC;EACE,aAAA;EACA,kBAAA;CnBqmFH;AmBlmFC;;EAEE,aAAA;CnBomFH;AkBr1ED;EAEI,aAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;ClBs1EH;AkB51ED;EASI,aAAA;EACA,kBAAA;ClBs1EH;AkBh2ED;;EAcI,aAAA;ClBs1EH;AkBp2ED;EAiBI,aAAA;EACA,iBAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;ClBs1EH;AkB70ED;EAEE,mBAAA;ClB80ED;AkBh1ED;EAMI,sBAAA;ClB60EH;AkBz0ED;EACE,mBAAA;EACA,OAAA;EACA,SAAA;EACA,WAAA;EACA,eAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;EACA,mBAAA;EACA,qBAAA;ClB20ED;AkBz0ED;;;EAGE,YAAA;EACA,aAAA;EACA,kBAAA;ClB20ED;AkBz0ED;;;EAGE,YAAA;EACA,aAAA;EACA,kBAAA;ClB20ED;AkBv0ED;;;;;;;;;;ECpZI,eAAA;CnBuuFH;AkBn1ED;EChZI,sBAAA;Ed+CF,yDAAA;EACQ,iDAAA;CLwrFT;AmBtuFG;EACE,sBAAA;Ed4CJ,0EAAA;EACQ,kEAAA;CL6rFT;AkB71ED;ECtYI,eAAA;EACA,sBAAA;EACA,0BAAA;CnBsuFH;AkBl2ED;EChYI,eAAA;CnBquFH;AkBl2ED;;;;;;;;;;ECvZI,eAAA;CnBqwFH;AkB92ED;ECnZI,sBAAA;Ed+CF,yDAAA;EACQ,iDAAA;CLstFT;AmBpwFG;EACE,sBAAA;Ed4CJ,0EAAA;EACQ,kEAAA;CL2tFT;AkBx3ED;ECzYI,eAAA;EACA,sBAAA;EACA,0BAAA;CnBowFH;AkB73ED;ECnYI,eAAA;CnBmwFH;AkB73ED;;;;;;;;;;EC1ZI,eAAA;CnBmyFH;AkBz4ED;ECtZI,sBAAA;Ed+CF,yDAAA;EACQ,iDAAA;CLovFT;AmBlyFG;EACE,sBAAA;Ed4CJ,0EAAA;EACQ,kEAAA;CLyvFT;AkBn5ED;EC5YI,eAAA;EACA,sBAAA;EACA,0BAAA;CnBkyFH;AkBx5ED;ECtYI,eAAA;CnBiyFH;AkBp5EC;EACG,UAAA;ClBs5EJ;AkBp5EC;EACG,OAAA;ClBs5EJ;AkB54ED;EACE,eAAA;EACA,gBAAA;EACA,oBAAA;EACA,eAAA;ClB84ED;AkB3zED;EAAA;IA9DM,sBAAA;IACA,iBAAA;IACA,uBAAA;GlB63EH;EkBj0EH;IAvDM,sBAAA;IACA,YAAA;IACA,uBAAA;GlB23EH;EkBt0EH;IAhDM,sBAAA;GlBy3EH;EkBz0EH;IA5CM,sBAAA;IACA,uBAAA;GlBw3EH;EkB70EH;;;IAtCQ,YAAA;GlBw3EL;EkBl1EH;IAhCM,YAAA;GlBq3EH;EkBr1EH;IA5BM,iBAAA;IACA,uBAAA;GlBo3EH;EkBz1EH;;IApBM,sBAAA;IACA,cAAA;IACA,iBAAA;IACA,uBAAA;GlBi3EH;EkBh2EH;;IAdQ,gBAAA;GlBk3EL;EkBp2EH;;IATM,mBAAA;IACA,eAAA;GlBi3EH;EkBz2EH;IAHM,OAAA;GlB+2EH;CACF;AkBr2ED;;;;EASI,cAAA;EACA,iBAAA;EACA,iBAAA;ClBk2EH;AkB72ED;;EAiBI,iBAAA;ClBg2EH;AkBj3ED;EJhhBE,mBAAA;EACA,oBAAA;Cdo4FD;AkB90EC;EAAA;IAVI,kBAAA;IACA,iBAAA;IACA,iBAAA;GlB41EH;CACF;AkB53ED;EAwCI,YAAA;ClBu1EH;AkBz0EC;EAAA;IAJM,yBAAA;IACA,gBAAA;GlBi1EL;CACF;AkBv0EC;EAAA;IAJM,iBAAA;IACA,gBAAA;GlB+0EL;CACF;AoBl6FD;EACE,sBAAA;EACA,iBAAA;EACA,oBAAA;EACA,mBAAA;EACA,uBAAA;EACA,+BAAA;MAAA,2BAAA;EACA,gBAAA;EACA,uBAAA;EACA,8BAAA;EACA,oBAAA;EC6CA,kBAAA;EACA,gBAAA;EACA,wBAAA;EACA,mBAAA;EhB4JA,0BAAA;EACG,uBAAA;EACC,sBAAA;EACI,kBAAA;CL6tFT;AoBr6FG;;;;;;EdrBF,qBAAA;EAEA,2CAAA;EACA,qBAAA;CNi8FD;AoBz6FC;;;EAGE,eAAA;EACA,sBAAA;CpB26FH;AoBx6FC;;EAEE,WAAA;EACA,uBAAA;Ef2BF,yDAAA;EACQ,iDAAA;CLg5FT;AoBx6FC;;;EAGE,oBAAA;EE7CF,cAAA;EAGA,0BAAA;EjB8DA,yBAAA;EACQ,iBAAA;CLy5FT;AoBx6FG;;EAEE,qBAAA;CpB06FL;AoBj6FD;EC3DE,eAAA;EACA,0BAAA;EACA,sBAAA;CrB+9FD;AqB79FC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB+9FP;AqB79FC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB+9FP;AqB79FC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB+9FP;AqB79FG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBq+FT;AqBl+FC;;;EAGE,uBAAA;CrBo+FH;AqB/9FG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrB6+FT;AoB/9FD;ECTI,eAAA;EACA,0BAAA;CrB2+FH;AoBh+FD;EC9DE,eAAA;EACA,0BAAA;EACA,sBAAA;CrBiiGD;AqB/hGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBiiGP;AqB/hGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBiiGP;AqB/hGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBiiGP;AqB/hGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBuiGT;AqBpiGC;;;EAGE,uBAAA;CrBsiGH;AqBjiGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrB+iGT;AoB9hGD;ECZI,eAAA;EACA,0BAAA;CrB6iGH;AoB9hGD;EClEE,eAAA;EACA,0BAAA;EACA,sBAAA;CrBmmGD;AqBjmGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBmmGP;AqBjmGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBmmGP;AqBjmGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBmmGP;AqBjmGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBymGT;AqBtmGC;;;EAGE,uBAAA;CrBwmGH;AqBnmGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrBinGT;AoB5lGD;EChBI,eAAA;EACA,0BAAA;CrB+mGH;AoB5lGD;ECtEE,eAAA;EACA,0BAAA;EACA,sBAAA;CrBqqGD;AqBnqGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBqqGP;AqBnqGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBqqGP;AqBnqGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBqqGP;AqBnqGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB2qGT;AqBxqGC;;;EAGE,uBAAA;CrB0qGH;AqBrqGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrBmrGT;AoB1pGD;ECpBI,eAAA;EACA,0BAAA;CrBirGH;AoB1pGD;EC1EE,eAAA;EACA,0BAAA;EACA,sBAAA;CrBuuGD;AqBruGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBuuGP;AqBruGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBuuGP;AqBruGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBuuGP;AqBruGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB6uGT;AqB1uGC;;;EAGE,uBAAA;CrB4uGH;AqBvuGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrBqvGT;AoBxtGD;ECxBI,eAAA;EACA,0BAAA;CrBmvGH;AoBxtGD;EC9EE,eAAA;EACA,0BAAA;EACA,sBAAA;CrByyGD;AqBvyGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrByyGP;AqBvyGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrByyGP;AqBvyGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrByyGP;AqBvyGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB+yGT;AqB5yGC;;;EAGE,uBAAA;CrB8yGH;AqBzyGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrBuzGT;AoBtxGD;EC5BI,eAAA;EACA,0BAAA;CrBqzGH;AoBjxGD;EACE,eAAA;EACA,oBAAA;EACA,iBAAA;CpBmxGD;AoBjxGC;;;;;EAKE,8BAAA;EfnCF,yBAAA;EACQ,iBAAA;CLuzGT;AoBlxGC;;;;EAIE,0BAAA;CpBoxGH;AoBlxGC;;EAEE,eAAA;EACA,2BAAA;EACA,8BAAA;CpBoxGH;AoBhxGG;;;;EAEE,eAAA;EACA,sBAAA;CpBoxGL;AoB3wGD;;ECrEE,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;CrBo1GD;AoB9wGD;;ECzEE,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CrB21GD;AoBjxGD;;EC7EE,iBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CrBk2GD;AoBhxGD;EACE,eAAA;EACA,YAAA;CpBkxGD;AoB9wGD;EACE,gBAAA;CpBgxGD;AoBzwGC;;;EACE,YAAA;CpB6wGH;AuBv6GD;EACE,WAAA;ElBoLA,yCAAA;EACK,oCAAA;EACG,iCAAA;CLsvGT;AuB16GC;EACE,WAAA;CvB46GH;AuBx6GD;EACE,cAAA;CvB06GD;AuBx6GC;EAAY,eAAA;CvB26Gb;AuB16GC;EAAY,mBAAA;CvB66Gb;AuB56GC;EAAY,yBAAA;CvB+6Gb;AuB56GD;EACE,mBAAA;EACA,UAAA;EACA,iBAAA;ElBuKA,gDAAA;EACQ,2CAAA;KAAA,wCAAA;EAOR,mCAAA;EACQ,8BAAA;KAAA,2BAAA;EAGR,yCAAA;EACQ,oCAAA;KAAA,iCAAA;CLgwGT;AwB18GD;EACE,sBAAA;EACA,SAAA;EACA,UAAA;EACA,iBAAA;EACA,uBAAA;EACA,uBAAA;EACA,yBAAA;EACA,oCAAA;EACA,mCAAA;CxB48GD;AwBx8GD;;EAEE,mBAAA;CxB08GD;AwBt8GD;EACE,WAAA;CxBw8GD;AwBp8GD;EACE,mBAAA;EACA,UAAA;EACA,QAAA;EACA,cAAA;EACA,cAAA;EACA,YAAA;EACA,iBAAA;EACA,eAAA;EACA,gBAAA;EACA,iBAAA;EACA,gBAAA;EACA,iBAAA;EACA,0BAAA;EACA,0BAAA;EACA,sCAAA;EACA,mBAAA;EnBsBA,oDAAA;EACQ,4CAAA;EmBrBR,qCAAA;UAAA,6BAAA;CxBu8GD;AwBl8GC;EACE,SAAA;EACA,WAAA;CxBo8GH;AwB79GD;ECzBE,YAAA;EACA,cAAA;EACA,iBAAA;EACA,0BAAA;CzBy/GD;AwBn+GD;EAmCI,eAAA;EACA,kBAAA;EACA,YAAA;EACA,oBAAA;EACA,wBAAA;EACA,eAAA;EACA,oBAAA;CxBm8GH;AwB77GC;;EAEE,sBAAA;EACA,eAAA;EACA,0BAAA;CxB+7GH;AwBz7GC;;;EAGE,eAAA;EACA,sBAAA;EACA,WAAA;EACA,0BAAA;CxB27GH;AwBl7GC;;;EAGE,eAAA;CxBo7GH;AwBh7GC;;EAEE,sBAAA;EACA,8BAAA;EACA,uBAAA;EE3GF,oEAAA;EF6GE,oBAAA;CxBk7GH;AwB76GD;EAGI,eAAA;CxB66GH;AwBh7GD;EAQI,WAAA;CxB26GH;AwBn6GD;EACE,WAAA;EACA,SAAA;CxBq6GD;AwB75GD;EACE,QAAA;EACA,YAAA;CxB+5GD;AwB35GD;EACE,eAAA;EACA,kBAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,oBAAA;CxB65GD;AwBz5GD;EACE,gBAAA;EACA,QAAA;EACA,SAAA;EACA,UAAA;EACA,OAAA;EACA,aAAA;CxB25GD;AwBv5GD;EACE,SAAA;EACA,WAAA;CxBy5GD;AwBj5GD;;EAII,cAAA;EACA,0BAAA;EACA,4BAAA;EACA,YAAA;CxBi5GH;AwBx5GD;;EAWI,UAAA;EACA,aAAA;EACA,mBAAA;CxBi5GH;AwB53GD;EAXE;IApEA,WAAA;IACA,SAAA;GxB+8GC;EwB54GD;IA1DA,QAAA;IACA,YAAA;GxBy8GC;CACF;A2BzlHD;;EAEE,mBAAA;EACA,sBAAA;EACA,uBAAA;C3B2lHD;A2B/lHD;;EAMI,mBAAA;EACA,YAAA;C3B6lHH;A2B3lHG;;;;;;;;EAIE,WAAA;C3BimHL;A2B3lHD;;;;EAKI,kBAAA;C3B4lHH;A2BvlHD;EACE,kBAAA;C3BylHD;A2B1lHD;;;EAOI,YAAA;C3BwlHH;A2B/lHD;;;EAYI,iBAAA;C3BwlHH;A2BplHD;EACE,iBAAA;C3BslHD;A2BllHD;EACE,eAAA;C3BolHD;A2BnlHC;EClDA,8BAAA;EACG,2BAAA;C5BwoHJ;A2BllHD;;EC/CE,6BAAA;EACG,0BAAA;C5BqoHJ;A2BjlHD;EACE,YAAA;C3BmlHD;A2BjlHD;EACE,iBAAA;C3BmlHD;A2BjlHD;;ECnEE,8BAAA;EACG,2BAAA;C5BwpHJ;A2BhlHD;ECjEE,6BAAA;EACG,0BAAA;C5BopHJ;A2B/kHD;;EAEE,WAAA;C3BilHD;A2BhkHD;EACE,kBAAA;EACA,mBAAA;C3BkkHD;A2BhkHD;EACE,mBAAA;EACA,oBAAA;C3BkkHD;A2B7jHD;EtB/CE,yDAAA;EACQ,iDAAA;CL+mHT;A2B7jHC;EtBnDA,yBAAA;EACQ,iBAAA;CLmnHT;A2B1jHD;EACE,eAAA;C3B4jHD;A2BzjHD;EACE,wBAAA;EACA,uBAAA;C3B2jHD;A2BxjHD;EACE,wBAAA;C3B0jHD;A2BnjHD;;;EAII,eAAA;EACA,YAAA;EACA,YAAA;EACA,gBAAA;C3BojHH;A2B3jHD;EAcM,YAAA;C3BgjHL;A2B9jHD;;;;EAsBI,iBAAA;EACA,eAAA;C3B8iHH;A2BziHC;EACE,iBAAA;C3B2iHH;A2BziHC;EACE,6BAAA;ECpKF,8BAAA;EACC,6BAAA;C5BgtHF;A2B1iHC;EACE,+BAAA;EChLF,2BAAA;EACC,0BAAA;C5B6tHF;A2B1iHD;EACE,iBAAA;C3B4iHD;A2B1iHD;;EC/KE,8BAAA;EACC,6BAAA;C5B6tHF;A2BziHD;EC7LE,2BAAA;EACC,0BAAA;C5ByuHF;A2BriHD;EACE,eAAA;EACA,YAAA;EACA,oBAAA;EACA,0BAAA;C3BuiHD;A2B3iHD;;EAOI,YAAA;EACA,oBAAA;EACA,UAAA;C3BwiHH;A2BjjHD;EAYI,YAAA;C3BwiHH;A2BpjHD;EAgBI,WAAA;C3BuiHH;A2BthHD;;;;EAKM,mBAAA;EACA,uBAAA;EACA,qBAAA;C3BuhHL;A6BjwHD;EACE,mBAAA;EACA,eAAA;EACA,0BAAA;C7BmwHD;A6BhwHC;EACE,YAAA;EACA,gBAAA;EACA,iBAAA;C7BkwHH;A6B3wHD;EAeI,mBAAA;EACA,WAAA;EAKA,YAAA;EAEA,YAAA;EACA,iBAAA;C7B0vHH;A6BjvHD;;;EV8BE,aAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;CnBwtHD;AmBttHC;;;EACE,aAAA;EACA,kBAAA;CnB0tHH;AmBvtHC;;;;;;EAEE,aAAA;CnB6tHH;A6BnwHD;;;EVyBE,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CnB+uHD;AmB7uHC;;;EACE,aAAA;EACA,kBAAA;CnBivHH;AmB9uHC;;;;;;EAEE,aAAA;CnBovHH;A6BjxHD;;;EAGE,oBAAA;C7BmxHD;A6BjxHC;;;EACE,iBAAA;C7BqxHH;A6BjxHD;;EAEE,UAAA;EACA,oBAAA;EACA,uBAAA;C7BmxHD;A6B9wHD;EACE,kBAAA;EACA,gBAAA;EACA,oBAAA;EACA,eAAA;EACA,eAAA;EACA,mBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;C7BgxHD;A6B7wHC;EACE,kBAAA;EACA,gBAAA;EACA,mBAAA;C7B+wHH;A6B7wHC;EACE,mBAAA;EACA,gBAAA;EACA,mBAAA;C7B+wHH;A6BnyHD;;EA0BI,cAAA;C7B6wHH;A6BxwHD;;;;;;;EDhGE,8BAAA;EACG,2BAAA;C5Bi3HJ;A6BzwHD;EACE,gBAAA;C7B2wHD;A6BzwHD;;;;;;;EDpGE,6BAAA;EACG,0BAAA;C5Bs3HJ;A6B1wHD;EACE,eAAA;C7B4wHD;A6BvwHD;EACE,mBAAA;EAGA,aAAA;EACA,oBAAA;C7BuwHD;A6B5wHD;EAUI,mBAAA;C7BqwHH;A6B/wHD;EAYM,kBAAA;C7BswHL;A6BnwHG;;;EAGE,WAAA;C7BqwHL;A6BhwHC;;EAGI,mBAAA;C7BiwHL;A6B9vHC;;EAGI,WAAA;EACA,kBAAA;C7B+vHL;A8B15HD;EACE,iBAAA;EACA,gBAAA;EACA,iBAAA;C9B45HD;A8B/5HD;EAOI,mBAAA;EACA,eAAA;C9B25HH;A8Bn6HD;EAWM,mBAAA;EACA,eAAA;EACA,mBAAA;C9B25HL;A8B15HK;;EAEE,sBAAA;EACA,0BAAA;C9B45HP;A8Bv5HG;EACE,eAAA;C9By5HL;A8Bv5HK;;EAEE,eAAA;EACA,sBAAA;EACA,8BAAA;EACA,oBAAA;C9By5HP;A8Bl5HG;;;EAGE,0BAAA;EACA,sBAAA;C9Bo5HL;A8B77HD;ELHE,YAAA;EACA,cAAA;EACA,iBAAA;EACA,0BAAA;CzBm8HD;A8Bn8HD;EA0DI,gBAAA;C9B44HH;A8Bn4HD;EACE,iCAAA;C9Bq4HD;A8Bt4HD;EAGI,YAAA;EAEA,oBAAA;C9Bq4HH;A8B14HD;EASM,kBAAA;EACA,wBAAA;EACA,8BAAA;EACA,2BAAA;C9Bo4HL;A8Bn4HK;EACE,sCAAA;C9Bq4HP;A8B/3HK;;;EAGE,eAAA;EACA,0BAAA;EACA,0BAAA;EACA,iCAAA;EACA,gBAAA;C9Bi4HP;A8B53HC;EAqDA,YAAA;EA8BA,iBAAA;C9B6yHD;A8Bh4HC;EAwDE,YAAA;C9B20HH;A8Bn4HC;EA0DI,mBAAA;EACA,mBAAA;C9B40HL;A8Bv4HC;EAgEE,UAAA;EACA,WAAA;C9B00HH;A8B9zHD;EAAA;IAPM,oBAAA;IACA,UAAA;G9By0HH;E8Bn0HH;IAJQ,iBAAA;G9B00HL;CACF;A8Bp5HC;EAuFE,gBAAA;EACA,mBAAA;C9Bg0HH;A8Bx5HC;;;EA8FE,0BAAA;C9B+zHH;A8BjzHD;EAAA;IATM,iCAAA;IACA,2BAAA;G9B8zHH;E8BtzHH;;;IAHM,6BAAA;G9B8zHH;CACF;A8B/5HD;EAEI,YAAA;C9Bg6HH;A8Bl6HD;EAMM,mBAAA;C9B+5HL;A8Br6HD;EASM,iBAAA;C9B+5HL;A8B15HK;;;EAGE,eAAA;EACA,0BAAA;C9B45HP;A8Bp5HD;EAEI,YAAA;C9Bq5HH;A8Bv5HD;EAIM,gBAAA;EACA,eAAA;C9Bs5HL;A8B14HD;EACE,YAAA;C9B44HD;A8B74HD;EAII,YAAA;C9B44HH;A8Bh5HD;EAMM,mBAAA;EACA,mBAAA;C9B64HL;A8Bp5HD;EAYI,UAAA;EACA,WAAA;C9B24HH;A8B/3HD;EAAA;IAPM,oBAAA;IACA,UAAA;G9B04HH;E8Bp4HH;IAJQ,iBAAA;G9B24HL;CACF;A8Bn4HD;EACE,iBAAA;C9Bq4HD;A8Bt4HD;EAKI,gBAAA;EACA,mBAAA;C9Bo4HH;A8B14HD;;;EAYI,0BAAA;C9Bm4HH;A8Br3HD;EAAA;IATM,iCAAA;IACA,2BAAA;G9Bk4HH;E8B13HH;;;IAHM,6BAAA;G9Bk4HH;CACF;A8Bz3HD;EAEI,cAAA;C9B03HH;A8B53HD;EAKI,eAAA;C9B03HH;A8Bj3HD;EAEE,iBAAA;EF3OA,2BAAA;EACC,0BAAA;C5B8lIF;A+BxlID;EACE,mBAAA;EACA,iBAAA;EACA,oBAAA;EACA,8BAAA;C/B0lID;A+BllID;EAAA;IAFI,mBAAA;G/BwlID;CACF;A+BzkID;EAAA;IAFI,YAAA;G/B+kID;CACF;A+BjkID;EACE,oBAAA;EACA,oBAAA;EACA,mBAAA;EACA,kCAAA;EACA,2DAAA;UAAA,mDAAA;EAEA,kCAAA;C/BkkID;A+BhkIC;EACE,iBAAA;C/BkkIH;A+BtiID;EAAA;IAxBI,YAAA;IACA,cAAA;IACA,yBAAA;YAAA,iBAAA;G/BkkID;E+BhkIC;IACE,0BAAA;IACA,wBAAA;IACA,kBAAA;IACA,6BAAA;G/BkkIH;E+B/jIC;IACE,oBAAA;G/BikIH;E+B5jIC;;;IAGE,gBAAA;IACA,iBAAA;G/B8jIH;CACF;A+B1jID;;EAGI,kBAAA;C/B2jIH;A+BtjIC;EAAA;;IAFI,kBAAA;G/B6jIH;CACF;A+BpjID;;;;EAII,oBAAA;EACA,mBAAA;C/BsjIH;A+BhjIC;EAAA;;;;IAHI,gBAAA;IACA,eAAA;G/B0jIH;CACF;A+B9iID;EACE,cAAA;EACA,sBAAA;C/BgjID;A+B3iID;EAAA;IAFI,iBAAA;G/BijID;CACF;A+B7iID;;EAEE,gBAAA;EACA,SAAA;EACA,QAAA;EACA,cAAA;C/B+iID;A+BziID;EAAA;;IAFI,iBAAA;G/BgjID;CACF;A+B9iID;EACE,OAAA;EACA,sBAAA;C/BgjID;A+B9iID;EACE,UAAA;EACA,iBAAA;EACA,sBAAA;C/BgjID;A+B1iID;EACE,YAAA;EACA,mBAAA;EACA,gBAAA;EACA,kBAAA;EACA,aAAA;C/B4iID;A+B1iIC;;EAEE,sBAAA;C/B4iIH;A+BrjID;EAaI,eAAA;C/B2iIH;A+BliID;EALI;;IAEE,mBAAA;G/B0iIH;CACF;A+BhiID;EACE,mBAAA;EACA,aAAA;EACA,mBAAA;EACA,kBAAA;EC9LA,gBAAA;EACA,mBAAA;ED+LA,8BAAA;EACA,uBAAA;EACA,8BAAA;EACA,mBAAA;C/BmiID;A+B/hIC;EACE,WAAA;C/BiiIH;A+B/iID;EAmBI,eAAA;EACA,YAAA;EACA,YAAA;EACA,mBAAA;C/B+hIH;A+BrjID;EAyBI,gBAAA;C/B+hIH;A+BzhID;EAAA;IAFI,cAAA;G/B+hID;CACF;A+BthID;EACE,oBAAA;C/BwhID;A+BzhID;EAII,kBAAA;EACA,qBAAA;EACA,kBAAA;C/BwhIH;A+B5/HC;EAAA;IAtBI,iBAAA;IACA,YAAA;IACA,YAAA;IACA,cAAA;IACA,8BAAA;IACA,UAAA;IACA,yBAAA;YAAA,iBAAA;G/BshIH;E+BtgID;;IAbM,2BAAA;G/BuhIL;E+B1gID;IAVM,kBAAA;G/BuhIL;E+BthIK;;IAEE,uBAAA;G/BwhIP;CACF;A+BtgID;EAAA;IAXI,YAAA;IACA,UAAA;G/BqhID;E+B3gIH;IAPM,YAAA;G/BqhIH;E+B9gIH;IALQ,kBAAA;IACA,qBAAA;G/BshIL;CACF;A+B3gID;EACE,mBAAA;EACA,oBAAA;EACA,mBAAA;EACA,kCAAA;EACA,qCAAA;E1B9NA,6FAAA;EACQ,qFAAA;E2B/DR,gBAAA;EACA,mBAAA;ChC4yID;AkB5xHD;EAAA;IA9DM,sBAAA;IACA,iBAAA;IACA,uBAAA;GlB81HH;EkBlyHH;IAvDM,sBAAA;IACA,YAAA;IACA,uBAAA;GlB41HH;EkBvyHH;IAhDM,sBAAA;GlB01HH;EkB1yHH;IA5CM,sBAAA;IACA,uBAAA;GlBy1HH;EkB9yHH;;;IAtCQ,YAAA;GlBy1HL;EkBnzHH;IAhCM,YAAA;GlBs1HH;EkBtzHH;IA5BM,iBAAA;IACA,uBAAA;GlBq1HH;EkB1zHH;;IApBM,sBAAA;IACA,cAAA;IACA,iBAAA;IACA,uBAAA;GlBk1HH;EkBj0HH;;IAdQ,gBAAA;GlBm1HL;EkBr0HH;;IATM,mBAAA;IACA,eAAA;GlBk1HH;EkB10HH;IAHM,OAAA;GlBg1HH;CACF;A+BpjIC;EAAA;IANI,mBAAA;G/B8jIH;E+B5jIG;IACE,iBAAA;G/B8jIL;CACF;A+B7iID;EAAA;IARI,YAAA;IACA,UAAA;IACA,eAAA;IACA,gBAAA;IACA,eAAA;IACA,kBAAA;I1BzPF,yBAAA;IACQ,iBAAA;GLmzIP;CACF;A+BnjID;EACE,cAAA;EHpUA,2BAAA;EACC,0BAAA;C5B03IF;A+BnjID;EACE,iBAAA;EHzUA,6BAAA;EACC,4BAAA;EAOD,8BAAA;EACC,6BAAA;C5By3IF;A+B/iID;EChVE,gBAAA;EACA,mBAAA;ChCk4ID;A+BhjIC;ECnVA,iBAAA;EACA,oBAAA;ChCs4ID;A+BjjIC;ECtVA,iBAAA;EACA,oBAAA;ChC04ID;A+B3iID;EChWE,iBAAA;EACA,oBAAA;ChC84ID;A+BviID;EAAA;IAJI,YAAA;IACA,kBAAA;IACA,mBAAA;G/B+iID;CACF;A+BlhID;EAhBE;IExWA,uBAAA;GjC84IC;E+BriID;IE5WA,wBAAA;IF8WE,oBAAA;G/BuiID;E+BziID;IAKI,gBAAA;G/BuiIH;CACF;A+B9hID;EACE,0BAAA;EACA,sBAAA;C/BgiID;A+BliID;EAKI,eAAA;C/BgiIH;A+B/hIG;;EAEE,eAAA;EACA,8BAAA;C/BiiIL;A+B1iID;EAcI,eAAA;C/B+hIH;A+B7iID;EAmBM,eAAA;C/B6hIL;A+B3hIK;;EAEE,eAAA;EACA,8BAAA;C/B6hIP;A+BzhIK;;;EAGE,eAAA;EACA,0BAAA;C/B2hIP;A+BvhIK;;;EAGE,eAAA;EACA,8BAAA;C/ByhIP;A+BjkID;EA8CI,sBAAA;C/BshIH;A+BrhIG;;EAEE,0BAAA;C/BuhIL;A+BxkID;EAoDM,0BAAA;C/BuhIL;A+B3kID;;EA0DI,sBAAA;C/BqhIH;A+B9gIK;;;EAGE,0BAAA;EACA,eAAA;C/BghIP;A+B/+HC;EAAA;IAzBQ,eAAA;G/B4gIP;E+B3gIO;;IAEE,eAAA;IACA,8BAAA;G/B6gIT;E+BzgIO;;;IAGE,eAAA;IACA,0BAAA;G/B2gIT;E+BvgIO;;;IAGE,eAAA;IACA,8BAAA;G/BygIT;CACF;A+B3mID;EA8GI,eAAA;C/BggIH;A+B//HG;EACE,eAAA;C/BigIL;A+BjnID;EAqHI,eAAA;C/B+/HH;A+B9/HG;;EAEE,eAAA;C/BggIL;A+B5/HK;;;;EAEE,eAAA;C/BggIP;A+Bx/HD;EACE,0BAAA;EACA,sBAAA;C/B0/HD;A+B5/HD;EAKI,eAAA;C/B0/HH;A+Bz/HG;;EAEE,eAAA;EACA,8BAAA;C/B2/HL;A+BpgID;EAcI,eAAA;C/By/HH;A+BvgID;EAmBM,eAAA;C/Bu/HL;A+Br/HK;;EAEE,eAAA;EACA,8BAAA;C/Bu/HP;A+Bn/HK;;;EAGE,eAAA;EACA,0BAAA;C/Bq/HP;A+Bj/HK;;;EAGE,eAAA;EACA,8BAAA;C/Bm/HP;A+B3hID;EA+CI,sBAAA;C/B++HH;A+B9+HG;;EAEE,0BAAA;C/Bg/HL;A+BliID;EAqDM,0BAAA;C/Bg/HL;A+BriID;;EA2DI,sBAAA;C/B8+HH;A+Bx+HK;;;EAGE,0BAAA;EACA,eAAA;C/B0+HP;A+Bn8HC;EAAA;IA/BQ,sBAAA;G/Bs+HP;E+Bv8HD;IA5BQ,0BAAA;G/Bs+HP;E+B18HD;IAzBQ,eAAA;G/Bs+HP;E+Br+HO;;IAEE,eAAA;IACA,8BAAA;G/Bu+HT;E+Bn+HO;;;IAGE,eAAA;IACA,0BAAA;G/Bq+HT;E+Bj+HO;;;IAGE,eAAA;IACA,8BAAA;G/Bm+HT;CACF;A+B3kID;EA+GI,eAAA;C/B+9HH;A+B99HG;EACE,eAAA;C/Bg+HL;A+BjlID;EAsHI,eAAA;C/B89HH;A+B79HG;;EAEE,eAAA;C/B+9HL;A+B39HK;;;;EAEE,eAAA;C/B+9HP;AkCzmJD;EACE,kBAAA;EACA,oBAAA;EACA,iBAAA;EACA,0BAAA;EACA,mBAAA;ClC2mJD;AkChnJD;EAQI,sBAAA;ClC2mJH;AkCnnJD;EAWM,kBAAA;EACA,eAAA;EACA,eAAA;ClC2mJL;AkCxnJD;EAkBI,eAAA;ClCymJH;AmC7nJD;EACE,sBAAA;EACA,gBAAA;EACA,eAAA;EACA,mBAAA;CnC+nJD;AmCnoJD;EAOI,gBAAA;CnC+nJH;AmCtoJD;;EAUM,mBAAA;EACA,YAAA;EACA,kBAAA;EACA,wBAAA;EACA,sBAAA;EACA,eAAA;EACA,0BAAA;EACA,0BAAA;EACA,kBAAA;CnCgoJL;AmC9nJG;;EAGI,eAAA;EPXN,+BAAA;EACG,4BAAA;C5B2oJJ;AmC7nJG;;EPvBF,gCAAA;EACG,6BAAA;C5BwpJJ;AmCxnJG;;;;EAEE,WAAA;EACA,eAAA;EACA,0BAAA;EACA,sBAAA;CnC4nJL;AmCtnJG;;;;;;EAGE,WAAA;EACA,eAAA;EACA,0BAAA;EACA,sBAAA;EACA,gBAAA;CnC2nJL;AmClrJD;;;;;;EAkEM,eAAA;EACA,0BAAA;EACA,sBAAA;EACA,oBAAA;CnCwnJL;AmC/mJD;;EC3EM,mBAAA;EACA,gBAAA;EACA,uBAAA;CpC8rJL;AoC5rJG;;ERKF,+BAAA;EACG,4BAAA;C5B2rJJ;AoC3rJG;;ERTF,gCAAA;EACG,6BAAA;C5BwsJJ;AmC1nJD;;EChFM,kBAAA;EACA,gBAAA;EACA,iBAAA;CpC8sJL;AoC5sJG;;ERKF,+BAAA;EACG,4BAAA;C5B2sJJ;AoC3sJG;;ERTF,gCAAA;EACG,6BAAA;C5BwtJJ;AqC3tJD;EACE,gBAAA;EACA,eAAA;EACA,iBAAA;EACA,mBAAA;CrC6tJD;AqCjuJD;EAOI,gBAAA;CrC6tJH;AqCpuJD;;EAUM,sBAAA;EACA,kBAAA;EACA,0BAAA;EACA,0BAAA;EACA,oBAAA;CrC8tJL;AqC5uJD;;EAmBM,sBAAA;EACA,0BAAA;CrC6tJL;AqCjvJD;;EA2BM,aAAA;CrC0tJL;AqCrvJD;;EAkCM,YAAA;CrCutJL;AqCzvJD;;;;EA2CM,eAAA;EACA,0BAAA;EACA,oBAAA;CrCotJL;AsClwJD;EACE,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,kBAAA;EACA,eAAA;EACA,eAAA;EACA,mBAAA;EACA,oBAAA;EACA,yBAAA;EACA,qBAAA;CtCowJD;AsChwJG;;EAEE,eAAA;EACA,sBAAA;EACA,gBAAA;CtCkwJL;AsC7vJC;EACE,cAAA;CtC+vJH;AsC3vJC;EACE,mBAAA;EACA,UAAA;CtC6vJH;AsCtvJD;ECtCE,0BAAA;CvC+xJD;AuC5xJG;;EAEE,0BAAA;CvC8xJL;AsCzvJD;EC1CE,0BAAA;CvCsyJD;AuCnyJG;;EAEE,0BAAA;CvCqyJL;AsC5vJD;EC9CE,0BAAA;CvC6yJD;AuC1yJG;;EAEE,0BAAA;CvC4yJL;AsC/vJD;EClDE,0BAAA;CvCozJD;AuCjzJG;;EAEE,0BAAA;CvCmzJL;AsClwJD;ECtDE,0BAAA;CvC2zJD;AuCxzJG;;EAEE,0BAAA;CvC0zJL;AsCrwJD;EC1DE,0BAAA;CvCk0JD;AuC/zJG;;EAEE,0BAAA;CvCi0JL;AwCn0JD;EACE,sBAAA;EACA,gBAAA;EACA,iBAAA;EACA,gBAAA;EACA,kBAAA;EACA,eAAA;EACA,eAAA;EACA,uBAAA;EACA,oBAAA;EACA,mBAAA;EACA,0BAAA;EACA,oBAAA;CxCq0JD;AwCl0JC;EACE,cAAA;CxCo0JH;AwCh0JC;EACE,mBAAA;EACA,UAAA;CxCk0JH;AwC/zJC;;EAEE,OAAA;EACA,iBAAA;CxCi0JH;AwC5zJG;;EAEE,eAAA;EACA,sBAAA;EACA,gBAAA;CxC8zJL;AwCzzJC;;EAEE,eAAA;EACA,0BAAA;CxC2zJH;AwCxzJC;EACE,aAAA;CxC0zJH;AwCvzJC;EACE,kBAAA;CxCyzJH;AwCtzJC;EACE,iBAAA;CxCwzJH;AyCl3JD;EACE,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,eAAA;EACA,0BAAA;CzCo3JD;AyCz3JD;;EASI,eAAA;CzCo3JH;AyC73JD;EAaI,oBAAA;EACA,gBAAA;EACA,iBAAA;CzCm3JH;AyCl4JD;EAmBI,0BAAA;CzCk3JH;AyC/2JC;;EAEE,mBAAA;CzCi3JH;AyCz4JD;EA4BI,gBAAA;CzCg3JH;AyC91JD;EAAA;IAdI,kBAAA;IACA,qBAAA;GzCg3JD;EyC92JC;;IAEE,mBAAA;IACA,oBAAA;GzCg3JH;EyCx2JH;;IAHM,gBAAA;GzC+2JH;CACF;A0C15JD;EACE,eAAA;EACA,aAAA;EACA,oBAAA;EACA,wBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;ErCiLA,4CAAA;EACK,uCAAA;EACG,oCAAA;CL4uJT;A0Ct6JD;;EAaI,kBAAA;EACA,mBAAA;C1C65JH;A0Cz5JC;;;EAGE,sBAAA;C1C25JH;A0Ch7JD;EA0BI,aAAA;EACA,eAAA;C1Cy5JH;A2Cl7JD;EACE,cAAA;EACA,oBAAA;EACA,8BAAA;EACA,mBAAA;C3Co7JD;A2Cx7JD;EAQI,cAAA;EAEA,eAAA;C3Ck7JH;A2C57JD;EAeI,kBAAA;C3Cg7JH;A2C/7JD;;EAqBI,iBAAA;C3C86JH;A2Cn8JD;EAyBI,gBAAA;C3C66JH;A2Cr6JD;;EAEE,oBAAA;C3Cu6JD;A2Cz6JD;;EAMI,mBAAA;EACA,UAAA;EACA,aAAA;EACA,eAAA;C3Cu6JH;A2C/5JD;ECvDE,0BAAA;EACA,sBAAA;EACA,eAAA;C5Cy9JD;A2Cp6JD;EClDI,0BAAA;C5Cy9JH;A2Cv6JD;EC/CI,eAAA;C5Cy9JH;A2Ct6JD;EC3DE,0BAAA;EACA,sBAAA;EACA,eAAA;C5Co+JD;A2C36JD;ECtDI,0BAAA;C5Co+JH;A2C96JD;ECnDI,eAAA;C5Co+JH;A2C76JD;EC/DE,0BAAA;EACA,sBAAA;EACA,eAAA;C5C++JD;A2Cl7JD;EC1DI,0BAAA;C5C++JH;A2Cr7JD;ECvDI,eAAA;C5C++JH;A2Cp7JD;ECnEE,0BAAA;EACA,sBAAA;EACA,eAAA;C5C0/JD;A2Cz7JD;EC9DI,0BAAA;C5C0/JH;A2C57JD;EC3DI,eAAA;C5C0/JH;A6C5/JD;EACE;IAAQ,4BAAA;G7C+/JP;E6C9/JD;IAAQ,yBAAA;G7CigKP;CACF;A6C9/JD;EACE;IAAQ,4BAAA;G7CigKP;E6ChgKD;IAAQ,yBAAA;G7CmgKP;CACF;A6CtgKD;EACE;IAAQ,4BAAA;G7CigKP;E6ChgKD;IAAQ,yBAAA;G7CmgKP;CACF;A6C5/JD;EACE,iBAAA;EACA,aAAA;EACA,oBAAA;EACA,0BAAA;EACA,mBAAA;ExCsCA,uDAAA;EACQ,+CAAA;CLy9JT;A6C3/JD;EACE,YAAA;EACA,UAAA;EACA,aAAA;EACA,gBAAA;EACA,kBAAA;EACA,eAAA;EACA,mBAAA;EACA,0BAAA;ExCyBA,uDAAA;EACQ,+CAAA;EAyHR,oCAAA;EACK,+BAAA;EACG,4BAAA;CL62JT;A6Cx/JD;;ECCI,8MAAA;EACA,yMAAA;EACA,sMAAA;EDAF,mCAAA;UAAA,2BAAA;C7C4/JD;A6Cr/JD;;ExC5CE,2DAAA;EACK,sDAAA;EACG,mDAAA;CLqiKT;A6Cl/JD;EErEE,0BAAA;C/C0jKD;A+CvjKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9C0gKH;A6Ct/JD;EEzEE,0BAAA;C/CkkKD;A+C/jKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9CkhKH;A6C1/JD;EE7EE,0BAAA;C/C0kKD;A+CvkKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9C0hKH;A6C9/JD;EEjFE,0BAAA;C/CklKD;A+C/kKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9CkiKH;AgD1lKD;EAEE,iBAAA;ChD2lKD;AgDzlKC;EACE,cAAA;ChD2lKH;AgDvlKD;;EAEE,QAAA;EACA,iBAAA;ChDylKD;AgDtlKD;EACE,eAAA;ChDwlKD;AgDrlKD;EACE,eAAA;ChDulKD;AgDplKC;EACE,gBAAA;ChDslKH;AgDllKD;;EAEE,mBAAA;ChDolKD;AgDjlKD;;EAEE,oBAAA;ChDmlKD;AgDhlKD;;;EAGE,oBAAA;EACA,oBAAA;ChDklKD;AgD/kKD;EACE,uBAAA;ChDilKD;AgD9kKD;EACE,uBAAA;ChDglKD;AgD5kKD;EACE,cAAA;EACA,mBAAA;ChD8kKD;AgDxkKD;EACE,gBAAA;EACA,iBAAA;ChD0kKD;AiDjoKD;EAEE,oBAAA;EACA,gBAAA;CjDkoKD;AiD1nKD;EACE,mBAAA;EACA,eAAA;EACA,mBAAA;EAEA,oBAAA;EACA,0BAAA;EACA,0BAAA;CjD2nKD;AiDxnKC;ErB3BA,6BAAA;EACC,4BAAA;C5BspKF;AiDznKC;EACE,iBAAA;ErBvBF,gCAAA;EACC,+BAAA;C5BmpKF;AiDlnKD;;EAEE,eAAA;CjDonKD;AiDtnKD;;EAKI,eAAA;CjDqnKH;AiDjnKC;;;;EAEE,sBAAA;EACA,eAAA;EACA,0BAAA;CjDqnKH;AiDjnKD;EACE,YAAA;EACA,iBAAA;CjDmnKD;AiD9mKC;;;EAGE,0BAAA;EACA,eAAA;EACA,oBAAA;CjDgnKH;AiDrnKC;;;EASI,eAAA;CjDinKL;AiD1nKC;;;EAYI,eAAA;CjDmnKL;AiD9mKC;;;EAGE,WAAA;EACA,eAAA;EACA,0BAAA;EACA,sBAAA;CjDgnKH;AiDtnKC;;;;;;;;;EAYI,eAAA;CjDqnKL;AiDjoKC;;;EAeI,eAAA;CjDunKL;AkDztKC;EACE,eAAA;EACA,0BAAA;ClD2tKH;AkDztKG;;EAEE,eAAA;ClD2tKL;AkD7tKG;;EAKI,eAAA;ClD4tKP;AkDztKK;;;;EAEE,eAAA;EACA,0BAAA;ClD6tKP;AkD3tKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClDguKP;AkDtvKC;EACE,eAAA;EACA,0BAAA;ClDwvKH;AkDtvKG;;EAEE,eAAA;ClDwvKL;AkD1vKG;;EAKI,eAAA;ClDyvKP;AkDtvKK;;;;EAEE,eAAA;EACA,0BAAA;ClD0vKP;AkDxvKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClD6vKP;AkDnxKC;EACE,eAAA;EACA,0BAAA;ClDqxKH;AkDnxKG;;EAEE,eAAA;ClDqxKL;AkDvxKG;;EAKI,eAAA;ClDsxKP;AkDnxKK;;;;EAEE,eAAA;EACA,0BAAA;ClDuxKP;AkDrxKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClD0xKP;AkDhzKC;EACE,eAAA;EACA,0BAAA;ClDkzKH;AkDhzKG;;EAEE,eAAA;ClDkzKL;AkDpzKG;;EAKI,eAAA;ClDmzKP;AkDhzKK;;;;EAEE,eAAA;EACA,0BAAA;ClDozKP;AkDlzKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClDuzKP;AiDttKD;EACE,cAAA;EACA,mBAAA;CjDwtKD;AiDttKD;EACE,iBAAA;EACA,iBAAA;CjDwtKD;AmDl1KD;EACE,oBAAA;EACA,0BAAA;EACA,8BAAA;EACA,mBAAA;E9C0DA,kDAAA;EACQ,0CAAA;CL2xKT;AmDj1KD;EACE,cAAA;CnDm1KD;AmD90KD;EACE,mBAAA;EACA,qCAAA;EvBpBA,6BAAA;EACC,4BAAA;C5Bq2KF;AmDp1KD;EAMI,eAAA;CnDi1KH;AmD50KD;EACE,cAAA;EACA,iBAAA;EACA,gBAAA;EACA,eAAA;CnD80KD;AmDl1KD;;;;;EAWI,eAAA;CnD80KH;AmDz0KD;EACE,mBAAA;EACA,0BAAA;EACA,8BAAA;EvBxCA,gCAAA;EACC,+BAAA;C5Bo3KF;AmDn0KD;;EAGI,iBAAA;CnDo0KH;AmDv0KD;;EAMM,oBAAA;EACA,iBAAA;CnDq0KL;AmDj0KG;;EAEI,cAAA;EvBvEN,6BAAA;EACC,4BAAA;C5B24KF;AmD/zKG;;EAEI,iBAAA;EvBvEN,gCAAA;EACC,+BAAA;C5By4KF;AmDx1KD;EvB1DE,2BAAA;EACC,0BAAA;C5Bq5KF;AmD3zKD;EAEI,oBAAA;CnD4zKH;AmDzzKD;EACE,oBAAA;CnD2zKD;AmDnzKD;;;EAII,iBAAA;CnDozKH;AmDxzKD;;;EAOM,mBAAA;EACA,oBAAA;CnDszKL;AmD9zKD;;EvBzGE,6BAAA;EACC,4BAAA;C5B26KF;AmDn0KD;;;;EAmBQ,4BAAA;EACA,6BAAA;CnDszKP;AmD10KD;;;;;;;;EAwBU,4BAAA;CnD4zKT;AmDp1KD;;;;;;;;EA4BU,6BAAA;CnDk0KT;AmD91KD;;EvBjGE,gCAAA;EACC,+BAAA;C5Bm8KF;AmDn2KD;;;;EAyCQ,+BAAA;EACA,gCAAA;CnDg0KP;AmD12KD;;;;;;;;EA8CU,+BAAA;CnDs0KT;AmDp3KD;;;;;;;;EAkDU,gCAAA;CnD40KT;AmD93KD;;;;EA2DI,8BAAA;CnDy0KH;AmDp4KD;;EA+DI,cAAA;CnDy0KH;AmDx4KD;;EAmEI,UAAA;CnDy0KH;AmD54KD;;;;;;;;;;;;EA0EU,eAAA;CnDg1KT;AmD15KD;;;;;;;;;;;;EA8EU,gBAAA;CnD01KT;AmDx6KD;;;;;;;;EAuFU,iBAAA;CnD21KT;AmDl7KD;;;;;;;;EAgGU,iBAAA;CnD41KT;AmD57KD;EAsGI,UAAA;EACA,iBAAA;CnDy1KH;AmD/0KD;EACE,oBAAA;CnDi1KD;AmDl1KD;EAKI,iBAAA;EACA,mBAAA;CnDg1KH;AmDt1KD;EASM,gBAAA;CnDg1KL;AmDz1KD;EAcI,iBAAA;CnD80KH;AmD51KD;;EAkBM,8BAAA;CnD80KL;AmDh2KD;EAuBI,cAAA;CnD40KH;AmDn2KD;EAyBM,iCAAA;CnD60KL;AmDt0KD;EC1PE,sBAAA;CpDmkLD;AoDjkLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDmkLH;AoDtkLC;EAMI,0BAAA;CpDmkLL;AoDzkLC;EASI,eAAA;EACA,0BAAA;CpDmkLL;AoDhkLC;EAEI,6BAAA;CpDikLL;AmDr1KD;EC7PE,sBAAA;CpDqlLD;AoDnlLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDqlLH;AoDxlLC;EAMI,0BAAA;CpDqlLL;AoD3lLC;EASI,eAAA;EACA,0BAAA;CpDqlLL;AoDllLC;EAEI,6BAAA;CpDmlLL;AmDp2KD;EChQE,sBAAA;CpDumLD;AoDrmLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDumLH;AoD1mLC;EAMI,0BAAA;CpDumLL;AoD7mLC;EASI,eAAA;EACA,0BAAA;CpDumLL;AoDpmLC;EAEI,6BAAA;CpDqmLL;AmDn3KD;ECnQE,sBAAA;CpDynLD;AoDvnLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDynLH;AoD5nLC;EAMI,0BAAA;CpDynLL;AoD/nLC;EASI,eAAA;EACA,0BAAA;CpDynLL;AoDtnLC;EAEI,6BAAA;CpDunLL;AmDl4KD;ECtQE,sBAAA;CpD2oLD;AoDzoLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpD2oLH;AoD9oLC;EAMI,0BAAA;CpD2oLL;AoDjpLC;EASI,eAAA;EACA,0BAAA;CpD2oLL;AoDxoLC;EAEI,6BAAA;CpDyoLL;AmDj5KD;ECzQE,sBAAA;CpD6pLD;AoD3pLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpD6pLH;AoDhqLC;EAMI,0BAAA;CpD6pLL;AoDnqLC;EASI,eAAA;EACA,0BAAA;CpD6pLL;AoD1pLC;EAEI,6BAAA;CpD2pLL;AqD3qLD;EACE,mBAAA;EACA,eAAA;EACA,UAAA;EACA,WAAA;EACA,iBAAA;CrD6qLD;AqDlrLD;;;;;EAYI,mBAAA;EACA,OAAA;EACA,QAAA;EACA,UAAA;EACA,aAAA;EACA,YAAA;EACA,UAAA;CrD6qLH;AqDxqLD;EACE,uBAAA;CrD0qLD;AqDtqLD;EACE,oBAAA;CrDwqLD;AsDnsLD;EACE,iBAAA;EACA,cAAA;EACA,oBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;EjDwDA,wDAAA;EACQ,gDAAA;CL8oLT;AsD7sLD;EASI,mBAAA;EACA,kCAAA;CtDusLH;AsDlsLD;EACE,cAAA;EACA,mBAAA;CtDosLD;AsDlsLD;EACE,aAAA;EACA,mBAAA;CtDosLD;AuD1tLD;EACE,aAAA;EACA,gBAAA;EACA,kBAAA;EACA,eAAA;EACA,eAAA;EACA,6BAAA;EjCRA,aAAA;EAGA,0BAAA;CtBmuLD;AuD3tLC;;EAEE,eAAA;EACA,sBAAA;EACA,gBAAA;EjCfF,aAAA;EAGA,0BAAA;CtB2uLD;AuDvtLC;EACE,WAAA;EACA,gBAAA;EACA,wBAAA;EACA,UAAA;EACA,yBAAA;CvDytLH;AwD9uLD;EACE,iBAAA;CxDgvLD;AwD5uLD;EACE,cAAA;EACA,iBAAA;EACA,gBAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA;EACA,cAAA;EACA,kCAAA;EAIA,WAAA;CxD2uLD;AwDxuLC;EnD+GA,sCAAA;EACI,kCAAA;EACC,iCAAA;EACG,8BAAA;EAkER,oDAAA;EAEK,0CAAA;EACG,oCAAA;CL2jLT;AwD9uLC;EnD2GA,mCAAA;EACI,+BAAA;EACC,8BAAA;EACG,2BAAA;CLsoLT;AwDlvLD;EACE,mBAAA;EACA,iBAAA;CxDovLD;AwDhvLD;EACE,mBAAA;EACA,YAAA;EACA,aAAA;CxDkvLD;AwD9uLD;EACE,mBAAA;EACA,0BAAA;EACA,0BAAA;EACA,qCAAA;EACA,mBAAA;EnDaA,iDAAA;EACQ,yCAAA;EmDZR,qCAAA;UAAA,6BAAA;EAEA,WAAA;CxDgvLD;AwD5uLD;EACE,gBAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA;EACA,cAAA;EACA,0BAAA;CxD8uLD;AwD5uLC;ElCrEA,WAAA;EAGA,yBAAA;CtBkzLD;AwD/uLC;ElCtEA,aAAA;EAGA,0BAAA;CtBszLD;AwD9uLD;EACE,cAAA;EACA,iCAAA;EACA,0BAAA;CxDgvLD;AwD7uLD;EACE,iBAAA;CxD+uLD;AwD3uLD;EACE,UAAA;EACA,wBAAA;CxD6uLD;AwDxuLD;EACE,mBAAA;EACA,cAAA;CxD0uLD;AwDtuLD;EACE,cAAA;EACA,kBAAA;EACA,8BAAA;CxDwuLD;AwD3uLD;EAQI,iBAAA;EACA,iBAAA;CxDsuLH;AwD/uLD;EAaI,kBAAA;CxDquLH;AwDlvLD;EAiBI,eAAA;CxDouLH;AwD/tLD;EACE,mBAAA;EACA,aAAA;EACA,YAAA;EACA,aAAA;EACA,iBAAA;CxDiuLD;AwD/sLD;EAZE;IACE,aAAA;IACA,kBAAA;GxD8tLD;EwD5tLD;InDvEA,kDAAA;IACQ,0CAAA;GLsyLP;EwD3tLD;IAAY,aAAA;GxD8tLX;CACF;AwDztLD;EAFE;IAAY,aAAA;GxD+tLX;CACF;AyD92LD;EACE,mBAAA;EACA,cAAA;EACA,eAAA;ECRA,4DAAA;EAEA,mBAAA;EACA,oBAAA;EACA,uBAAA;EACA,iBAAA;EACA,wBAAA;EACA,iBAAA;EACA,kBAAA;EACA,sBAAA;EACA,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,mBAAA;EACA,qBAAA;EACA,kBAAA;EDHA,gBAAA;EnCVA,WAAA;EAGA,yBAAA;CtBq4LD;AyD13LC;EnCdA,aAAA;EAGA,0BAAA;CtBy4LD;AyD73LC;EAAW,iBAAA;EAAmB,eAAA;CzDi4L/B;AyDh4LC;EAAW,iBAAA;EAAmB,eAAA;CzDo4L/B;AyDn4LC;EAAW,gBAAA;EAAmB,eAAA;CzDu4L/B;AyDt4LC;EAAW,kBAAA;EAAmB,eAAA;CzD04L/B;AyDt4LD;EACE,iBAAA;EACA,iBAAA;EACA,eAAA;EACA,mBAAA;EACA,0BAAA;EACA,mBAAA;CzDw4LD;AyDp4LD;EACE,mBAAA;EACA,SAAA;EACA,UAAA;EACA,0BAAA;EACA,oBAAA;CzDs4LD;AyDl4LC;EACE,UAAA;EACA,UAAA;EACA,kBAAA;EACA,wBAAA;EACA,0BAAA;CzDo4LH;AyDl4LC;EACE,UAAA;EACA,WAAA;EACA,oBAAA;EACA,wBAAA;EACA,0BAAA;CzDo4LH;AyDl4LC;EACE,UAAA;EACA,UAAA;EACA,oBAAA;EACA,wBAAA;EACA,0BAAA;CzDo4LH;AyDl4LC;EACE,SAAA;EACA,QAAA;EACA,iBAAA;EACA,4BAAA;EACA,4BAAA;CzDo4LH;AyDl4LC;EACE,SAAA;EACA,SAAA;EACA,iBAAA;EACA,4BAAA;EACA,2BAAA;CzDo4LH;AyDl4LC;EACE,OAAA;EACA,UAAA;EACA,kBAAA;EACA,wBAAA;EACA,6BAAA;CzDo4LH;AyDl4LC;EACE,OAAA;EACA,WAAA;EACA,iBAAA;EACA,wBAAA;EACA,6BAAA;CzDo4LH;AyDl4LC;EACE,OAAA;EACA,UAAA;EACA,iBAAA;EACA,wBAAA;EACA,6BAAA;CzDo4LH;A2Dj+LD;EACE,mBAAA;EACA,OAAA;EACA,QAAA;EACA,cAAA;EACA,cAAA;EACA,iBAAA;EACA,aAAA;EDXA,4DAAA;EAEA,mBAAA;EACA,oBAAA;EACA,uBAAA;EACA,iBAAA;EACA,wBAAA;EACA,iBAAA;EACA,kBAAA;EACA,sBAAA;EACA,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,mBAAA;EACA,qBAAA;EACA,kBAAA;ECAA,gBAAA;EAEA,0BAAA;EACA,qCAAA;UAAA,6BAAA;EACA,0BAAA;EACA,qCAAA;EACA,mBAAA;EtD8CA,kDAAA;EACQ,0CAAA;CLi8LT;A2D5+LC;EAAY,kBAAA;C3D++Lb;A2D9+LC;EAAY,kBAAA;C3Di/Lb;A2Dh/LC;EAAY,iBAAA;C3Dm/Lb;A2Dl/LC;EAAY,mBAAA;C3Dq/Lb;A2Dl/LD;EACE,UAAA;EACA,kBAAA;EACA,gBAAA;EACA,0BAAA;EACA,iCAAA;EACA,2BAAA;C3Do/LD;A2Dj/LD;EACE,kBAAA;C3Dm/LD;A2D3+LC;;EAEE,mBAAA;EACA,eAAA;EACA,SAAA;EACA,UAAA;EACA,0BAAA;EACA,oBAAA;C3D6+LH;A2D1+LD;EACE,mBAAA;C3D4+LD;A2D1+LD;EACE,mBAAA;EACA,YAAA;C3D4+LD;A2Dx+LC;EACE,UAAA;EACA,mBAAA;EACA,uBAAA;EACA,0BAAA;EACA,sCAAA;EACA,cAAA;C3D0+LH;A2Dz+LG;EACE,aAAA;EACA,YAAA;EACA,mBAAA;EACA,uBAAA;EACA,0BAAA;C3D2+LL;A2Dx+LC;EACE,SAAA;EACA,YAAA;EACA,kBAAA;EACA,qBAAA;EACA,4BAAA;EACA,wCAAA;C3D0+LH;A2Dz+LG;EACE,aAAA;EACA,UAAA;EACA,cAAA;EACA,qBAAA;EACA,4BAAA;C3D2+LL;A2Dx+LC;EACE,UAAA;EACA,mBAAA;EACA,oBAAA;EACA,6BAAA;EACA,yCAAA;EACA,WAAA;C3D0+LH;A2Dz+LG;EACE,aAAA;EACA,SAAA;EACA,mBAAA;EACA,oBAAA;EACA,6BAAA;C3D2+LL;A2Dv+LC;EACE,SAAA;EACA,aAAA;EACA,kBAAA;EACA,sBAAA;EACA,2BAAA;EACA,uCAAA;C3Dy+LH;A2Dx+LG;EACE,aAAA;EACA,WAAA;EACA,sBAAA;EACA,2BAAA;EACA,cAAA;C3D0+LL;A4DnmMD;EACE,mBAAA;C5DqmMD;A4DlmMD;EACE,mBAAA;EACA,iBAAA;EACA,YAAA;C5DomMD;A4DvmMD;EAMI,cAAA;EACA,mBAAA;EvD6KF,0CAAA;EACK,qCAAA;EACG,kCAAA;CLw7LT;A4D9mMD;;EAcM,eAAA;C5DomML;A4D1kMC;EAAA;IvDiKA,uDAAA;IAEK,6CAAA;IACG,uCAAA;IA7JR,oCAAA;IAEQ,4BAAA;IA+GR,4BAAA;IAEQ,oBAAA;GL69LP;E4DxmMG;;IvDmHJ,2CAAA;IACQ,mCAAA;IuDjHF,QAAA;G5D2mML;E4DzmMG;;IvD8GJ,4CAAA;IACQ,oCAAA;IuD5GF,QAAA;G5D4mML;E4D1mMG;;;IvDyGJ,wCAAA;IACQ,gCAAA;IuDtGF,QAAA;G5D6mML;CACF;A4DnpMD;;;EA6CI,eAAA;C5D2mMH;A4DxpMD;EAiDI,QAAA;C5D0mMH;A4D3pMD;;EAsDI,mBAAA;EACA,OAAA;EACA,YAAA;C5DymMH;A4DjqMD;EA4DI,WAAA;C5DwmMH;A4DpqMD;EA+DI,YAAA;C5DwmMH;A4DvqMD;;EAmEI,QAAA;C5DwmMH;A4D3qMD;EAuEI,YAAA;C5DumMH;A4D9qMD;EA0EI,WAAA;C5DumMH;A4D/lMD;EACE,mBAAA;EACA,OAAA;EACA,QAAA;EACA,UAAA;EACA,WAAA;EtC9FA,aAAA;EAGA,0BAAA;EsC6FA,gBAAA;EACA,eAAA;EACA,mBAAA;EACA,0CAAA;C5DkmMD;A4D7lMC;EdlGE,mGAAA;EACA,8FAAA;EACA,qHAAA;EAAA,+FAAA;EACA,4BAAA;EACA,uHAAA;C9CksMH;A4DjmMC;EACE,WAAA;EACA,SAAA;EdvGA,mGAAA;EACA,8FAAA;EACA,qHAAA;EAAA,+FAAA;EACA,4BAAA;EACA,uHAAA;C9C2sMH;A4DnmMC;;EAEE,WAAA;EACA,eAAA;EACA,sBAAA;EtCtHF,aAAA;EAGA,0BAAA;CtB0tMD;A4DpoMD;;;;EAsCI,mBAAA;EACA,SAAA;EACA,kBAAA;EACA,WAAA;EACA,sBAAA;C5DomMH;A4D9oMD;;EA8CI,UAAA;EACA,mBAAA;C5DomMH;A4DnpMD;;EAmDI,WAAA;EACA,oBAAA;C5DomMH;A4DxpMD;;EAwDI,YAAA;EACA,aAAA;EACA,eAAA;EACA,mBAAA;C5DomMH;A4D/lMG;EACE,iBAAA;C5DimML;A4D7lMG;EACE,iBAAA;C5D+lML;A4DrlMD;EACE,mBAAA;EACA,aAAA;EACA,UAAA;EACA,YAAA;EACA,WAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;C5DulMD;A4DhmMD;EAYI,sBAAA;EACA,YAAA;EACA,aAAA;EACA,YAAA;EACA,oBAAA;EACA,0BAAA;EACA,oBAAA;EACA,gBAAA;EAWA,0BAAA;EACA,mCAAA;C5D6kMH;A4D5mMD;EAkCI,UAAA;EACA,YAAA;EACA,aAAA;EACA,0BAAA;C5D6kMH;A4DtkMD;EACE,mBAAA;EACA,UAAA;EACA,WAAA;EACA,aAAA;EACA,YAAA;EACA,kBAAA;EACA,qBAAA;EACA,eAAA;EACA,mBAAA;EACA,0CAAA;C5DwkMD;A4DvkMC;EACE,kBAAA;C5DykMH;A4DhiMD;EAhCE;;;;IAKI,YAAA;IACA,aAAA;IACA,kBAAA;IACA,gBAAA;G5DkkMH;E4D1kMD;;IAYI,mBAAA;G5DkkMH;E4D9kMD;;IAgBI,oBAAA;G5DkkMH;E4D7jMD;IACE,UAAA;IACA,WAAA;IACA,qBAAA;G5D+jMD;E4D3jMD;IACE,aAAA;G5D6jMD;CACF;A6D3zMC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEE,aAAA;EACA,eAAA;C7Dy1MH;A6Dv1MC;;;;;;;;;;;;;;;EACE,YAAA;C7Du2MH;AiC/2MD;E6BRE,eAAA;EACA,kBAAA;EACA,mBAAA;C9D03MD;AiCj3MD;EACE,wBAAA;CjCm3MD;AiCj3MD;EACE,uBAAA;CjCm3MD;AiC32MD;EACE,yBAAA;CjC62MD;AiC32MD;EACE,0BAAA;CjC62MD;AiC32MD;EACE,mBAAA;CjC62MD;AiC32MD;E8BzBE,YAAA;EACA,mBAAA;EACA,kBAAA;EACA,8BAAA;EACA,UAAA;C/Du4MD;AiCz2MD;EACE,yBAAA;CjC22MD;AiCp2MD;EACE,gBAAA;CjCs2MD;AgEv4MD;EACE,oBAAA;ChEy4MD;AgEn4MD;;;;ECdE,yBAAA;CjEu5MD;AgEl4MD;;;;;;;;;;;;EAYE,yBAAA;ChEo4MD;AgE73MD;EAAA;IChDE,0BAAA;GjEi7MC;EiEh7MD;IAAU,0BAAA;GjEm7MT;EiEl7MD;IAAU,8BAAA;GjEq7MT;EiEp7MD;;IACU,+BAAA;GjEu7MT;CACF;AgEv4MD;EAAA;IAFI,0BAAA;GhE64MD;CACF;AgEv4MD;EAAA;IAFI,2BAAA;GhE64MD;CACF;AgEv4MD;EAAA;IAFI,iCAAA;GhE64MD;CACF;AgEt4MD;EAAA;ICrEE,0BAAA;GjE+8MC;EiE98MD;IAAU,0BAAA;GjEi9MT;EiEh9MD;IAAU,8BAAA;GjEm9MT;EiEl9MD;;IACU,+BAAA;GjEq9MT;CACF;AgEh5MD;EAAA;IAFI,0BAAA;GhEs5MD;CACF;AgEh5MD;EAAA;IAFI,2BAAA;GhEs5MD;CACF;AgEh5MD;EAAA;IAFI,iCAAA;GhEs5MD;CACF;AgE/4MD;EAAA;IC1FE,0BAAA;GjE6+MC;EiE5+MD;IAAU,0BAAA;GjE++MT;EiE9+MD;IAAU,8BAAA;GjEi/MT;EiEh/MD;;IACU,+BAAA;GjEm/MT;CACF;AgEz5MD;EAAA;IAFI,0BAAA;GhE+5MD;CACF;AgEz5MD;EAAA;IAFI,2BAAA;GhE+5MD;CACF;AgEz5MD;EAAA;IAFI,iCAAA;GhE+5MD;CACF;AgEx5MD;EAAA;IC/GE,0BAAA;GjE2gNC;EiE1gND;IAAU,0BAAA;GjE6gNT;EiE5gND;IAAU,8BAAA;GjE+gNT;EiE9gND;;IACU,+BAAA;GjEihNT;CACF;AgEl6MD;EAAA;IAFI,0BAAA;GhEw6MD;CACF;AgEl6MD;EAAA;IAFI,2BAAA;GhEw6MD;CACF;AgEl6MD;EAAA;IAFI,iCAAA;GhEw6MD;CACF;AgEj6MD;EAAA;IC5HE,yBAAA;GjEiiNC;CACF;AgEj6MD;EAAA;ICjIE,yBAAA;GjEsiNC;CACF;AgEj6MD;EAAA;ICtIE,yBAAA;GjE2iNC;CACF;AgEj6MD;EAAA;IC3IE,yBAAA;GjEgjNC;CACF;AgE95MD;ECnJE,yBAAA;CjEojND;AgE35MD;EAAA;ICjKE,0BAAA;GjEgkNC;EiE/jND;IAAU,0BAAA;GjEkkNT;EiEjkND;IAAU,8BAAA;GjEokNT;EiEnkND;;IACU,+BAAA;GjEskNT;CACF;AgEz6MD;EACE,yBAAA;ChE26MD;AgEt6MD;EAAA;IAFI,0BAAA;GhE46MD;CACF;AgE16MD;EACE,yBAAA;ChE46MD;AgEv6MD;EAAA;IAFI,2BAAA;GhE66MD;CACF;AgE36MD;EACE,yBAAA;ChE66MD;AgEx6MD;EAAA;IAFI,iCAAA;GhE86MD;CACF;AgEv6MD;EAAA;ICpLE,yBAAA;GjE+lNC;CACF","file":"bootstrap.css","sourcesContent":["/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n}\nbody {\n margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n vertical-align: baseline;\n}\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n[hidden],\ntemplate {\n display: none;\n}\na {\n background-color: transparent;\n}\na:active,\na:hover {\n outline: 0;\n}\nabbr[title] {\n border-bottom: 1px dotted;\n}\nb,\nstrong {\n font-weight: bold;\n}\ndfn {\n font-style: italic;\n}\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\nmark {\n background: #ff0;\n color: #000;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsup {\n top: -0.5em;\n}\nsub {\n bottom: -0.25em;\n}\nimg {\n border: 0;\n}\nsvg:not(:root) {\n overflow: hidden;\n}\nfigure {\n margin: 1em 40px;\n}\nhr {\n box-sizing: content-box;\n height: 0;\n}\npre {\n overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit;\n font: inherit;\n margin: 0;\n}\nbutton {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\ninput {\n line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box;\n padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n border: 0;\n padding: 0;\n}\ntextarea {\n overflow: auto;\n}\noptgroup {\n font-weight: bold;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\ntd,\nth {\n padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important;\n box-shadow: none !important;\n text-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n img {\n max-width: 100% !important;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n .navbar {\n display: none;\n }\n .btn > .caret,\n .dropup > .btn > .caret {\n border-top-color: #000 !important;\n }\n .label {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('../fonts/glyphicons-halflings-regular.eot');\n src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');\n}\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n content: \"\\2a\";\n}\n.glyphicon-plus:before {\n content: \"\\2b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n content: \"\\270f\";\n}\n.glyphicon-glass:before {\n content: \"\\e001\";\n}\n.glyphicon-music:before {\n content: \"\\e002\";\n}\n.glyphicon-search:before {\n content: \"\\e003\";\n}\n.glyphicon-heart:before {\n content: \"\\e005\";\n}\n.glyphicon-star:before {\n content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n content: \"\\e007\";\n}\n.glyphicon-user:before {\n content: \"\\e008\";\n}\n.glyphicon-film:before {\n content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n content: \"\\e010\";\n}\n.glyphicon-th:before {\n content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n content: \"\\e012\";\n}\n.glyphicon-ok:before {\n content: \"\\e013\";\n}\n.glyphicon-remove:before {\n content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n content: \"\\e016\";\n}\n.glyphicon-off:before {\n content: \"\\e017\";\n}\n.glyphicon-signal:before {\n content: \"\\e018\";\n}\n.glyphicon-cog:before {\n content: \"\\e019\";\n}\n.glyphicon-trash:before {\n content: \"\\e020\";\n}\n.glyphicon-home:before {\n content: \"\\e021\";\n}\n.glyphicon-file:before {\n content: \"\\e022\";\n}\n.glyphicon-time:before {\n content: \"\\e023\";\n}\n.glyphicon-road:before {\n content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n content: \"\\e025\";\n}\n.glyphicon-download:before {\n content: \"\\e026\";\n}\n.glyphicon-upload:before {\n content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n content: \"\\e032\";\n}\n.glyphicon-lock:before {\n content: \"\\e033\";\n}\n.glyphicon-flag:before {\n content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n content: \"\\e040\";\n}\n.glyphicon-tag:before {\n content: \"\\e041\";\n}\n.glyphicon-tags:before {\n content: \"\\e042\";\n}\n.glyphicon-book:before {\n content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n content: \"\\e044\";\n}\n.glyphicon-print:before {\n content: \"\\e045\";\n}\n.glyphicon-camera:before {\n content: \"\\e046\";\n}\n.glyphicon-font:before {\n content: \"\\e047\";\n}\n.glyphicon-bold:before {\n content: \"\\e048\";\n}\n.glyphicon-italic:before {\n content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n content: \"\\e055\";\n}\n.glyphicon-list:before {\n content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n content: \"\\e059\";\n}\n.glyphicon-picture:before {\n content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n content: \"\\e063\";\n}\n.glyphicon-tint:before {\n content: \"\\e064\";\n}\n.glyphicon-edit:before {\n content: \"\\e065\";\n}\n.glyphicon-share:before {\n content: \"\\e066\";\n}\n.glyphicon-check:before {\n content: \"\\e067\";\n}\n.glyphicon-move:before {\n content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n content: \"\\e070\";\n}\n.glyphicon-backward:before {\n content: \"\\e071\";\n}\n.glyphicon-play:before {\n content: \"\\e072\";\n}\n.glyphicon-pause:before {\n content: \"\\e073\";\n}\n.glyphicon-stop:before {\n content: \"\\e074\";\n}\n.glyphicon-forward:before {\n content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n content: \"\\e077\";\n}\n.glyphicon-eject:before {\n content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n content: \"\\e101\";\n}\n.glyphicon-gift:before {\n content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n content: \"\\e103\";\n}\n.glyphicon-fire:before {\n content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n content: \"\\e107\";\n}\n.glyphicon-plane:before {\n content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n content: \"\\e109\";\n}\n.glyphicon-random:before {\n content: \"\\e110\";\n}\n.glyphicon-comment:before {\n content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n content: \"\\e122\";\n}\n.glyphicon-bell:before {\n content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n content: \"\\e134\";\n}\n.glyphicon-globe:before {\n content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n content: \"\\e137\";\n}\n.glyphicon-filter:before {\n content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n content: \"\\e143\";\n}\n.glyphicon-link:before {\n content: \"\\e144\";\n}\n.glyphicon-phone:before {\n content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n content: \"\\e146\";\n}\n.glyphicon-usd:before {\n content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n content: \"\\e149\";\n}\n.glyphicon-sort:before {\n content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n content: \"\\e157\";\n}\n.glyphicon-expand:before {\n content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n content: \"\\e161\";\n}\n.glyphicon-flash:before {\n content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n content: \"\\e164\";\n}\n.glyphicon-record:before {\n content: \"\\e165\";\n}\n.glyphicon-save:before {\n content: \"\\e166\";\n}\n.glyphicon-open:before {\n content: \"\\e167\";\n}\n.glyphicon-saved:before {\n content: \"\\e168\";\n}\n.glyphicon-import:before {\n content: \"\\e169\";\n}\n.glyphicon-export:before {\n content: \"\\e170\";\n}\n.glyphicon-send:before {\n content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n content: \"\\e179\";\n}\n.glyphicon-header:before {\n content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n content: \"\\e183\";\n}\n.glyphicon-tower:before {\n content: \"\\e184\";\n}\n.glyphicon-stats:before {\n content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n content: \"\\e200\";\n}\n.glyphicon-cd:before {\n content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n content: \"\\e204\";\n}\n.glyphicon-copy:before {\n content: \"\\e205\";\n}\n.glyphicon-paste:before {\n content: \"\\e206\";\n}\n.glyphicon-alert:before {\n content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n content: \"\\e210\";\n}\n.glyphicon-king:before {\n content: \"\\e211\";\n}\n.glyphicon-queen:before {\n content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n content: \"\\e214\";\n}\n.glyphicon-knight:before {\n content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n content: \"\\e216\";\n}\n.glyphicon-tent:before {\n content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n content: \"\\e218\";\n}\n.glyphicon-bed:before {\n content: \"\\e219\";\n}\n.glyphicon-apple:before {\n content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n content: \"\\e227\";\n}\n.glyphicon-btc:before {\n content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n content: \"\\e227\";\n}\n.glyphicon-yen:before {\n content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n content: \"\\e232\";\n}\n.glyphicon-education:before {\n content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n content: \"\\e237\";\n}\n.glyphicon-oil:before {\n content: \"\\e238\";\n}\n.glyphicon-grain:before {\n content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n content: \"\\e253\";\n}\n.glyphicon-console:before {\n content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n content: \"\\e260\";\n}\n* {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n*:before,\n*:after {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.42857143;\n color: #333333;\n background-color: #ffffff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\na {\n color: #337ab7;\n text-decoration: none;\n}\na:hover,\na:focus {\n color: #23527c;\n text-decoration: underline;\n}\na:focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\nfigure {\n margin: 0;\n}\nimg {\n vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n display: block;\n max-width: 100%;\n height: auto;\n}\n.img-rounded {\n border-radius: 6px;\n}\n.img-thumbnail {\n padding: 4px;\n line-height: 1.42857143;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 4px;\n -webkit-transition: all 0.2s ease-in-out;\n -o-transition: all 0.2s ease-in-out;\n transition: all 0.2s ease-in-out;\n display: inline-block;\n max-width: 100%;\n height: auto;\n}\n.img-circle {\n border-radius: 50%;\n}\nhr {\n margin-top: 20px;\n margin-bottom: 20px;\n border: 0;\n border-top: 1px solid #eeeeee;\n}\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n}\n[role=\"button\"] {\n cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n font-weight: normal;\n line-height: 1;\n color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n margin-top: 20px;\n margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n margin-top: 10px;\n margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n font-size: 75%;\n}\nh1,\n.h1 {\n font-size: 36px;\n}\nh2,\n.h2 {\n font-size: 30px;\n}\nh3,\n.h3 {\n font-size: 24px;\n}\nh4,\n.h4 {\n font-size: 18px;\n}\nh5,\n.h5 {\n font-size: 14px;\n}\nh6,\n.h6 {\n font-size: 12px;\n}\np {\n margin: 0 0 10px;\n}\n.lead {\n margin-bottom: 20px;\n font-size: 16px;\n font-weight: 300;\n line-height: 1.4;\n}\n@media (min-width: 768px) {\n .lead {\n font-size: 21px;\n }\n}\nsmall,\n.small {\n font-size: 85%;\n}\nmark,\n.mark {\n background-color: #fcf8e3;\n padding: .2em;\n}\n.text-left {\n text-align: left;\n}\n.text-right {\n text-align: right;\n}\n.text-center {\n text-align: center;\n}\n.text-justify {\n text-align: justify;\n}\n.text-nowrap {\n white-space: nowrap;\n}\n.text-lowercase {\n text-transform: lowercase;\n}\n.text-uppercase {\n text-transform: uppercase;\n}\n.text-capitalize {\n text-transform: capitalize;\n}\n.text-muted {\n color: #777777;\n}\n.text-primary {\n color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n color: #286090;\n}\n.text-success {\n color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n color: #2b542c;\n}\n.text-info {\n color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n color: #245269;\n}\n.text-warning {\n color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n color: #66512c;\n}\n.text-danger {\n color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n color: #843534;\n}\n.bg-primary {\n color: #fff;\n background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n background-color: #286090;\n}\n.bg-success {\n background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n background-color: #c1e2b3;\n}\n.bg-info {\n background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n background-color: #afd9ee;\n}\n.bg-warning {\n background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n background-color: #f7ecb5;\n}\n.bg-danger {\n background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n background-color: #e4b9b9;\n}\n.page-header {\n padding-bottom: 9px;\n margin: 40px 0 20px;\n border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n margin-top: 0;\n margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n margin-bottom: 0;\n}\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n.list-inline {\n padding-left: 0;\n list-style: none;\n margin-left: -5px;\n}\n.list-inline > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n}\ndl {\n margin-top: 0;\n margin-bottom: 20px;\n}\ndt,\ndd {\n line-height: 1.42857143;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .dl-horizontal dt {\n float: left;\n width: 160px;\n clear: left;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .dl-horizontal dd {\n margin-left: 180px;\n }\n}\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted #777777;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\nblockquote {\n padding: 10px 20px;\n margin: 0 0 20px;\n font-size: 17.5px;\n border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n display: block;\n font-size: 80%;\n line-height: 1.42857143;\n color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid #eeeeee;\n border-left: 0;\n text-align: right;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n content: '\\00A0 \\2014';\n}\naddress {\n margin-bottom: 20px;\n font-style: normal;\n line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: #c7254e;\n background-color: #f9f2f4;\n border-radius: 4px;\n}\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: #ffffff;\n background-color: #333333;\n border-radius: 3px;\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n}\npre {\n display: block;\n padding: 9.5px;\n margin: 0 0 10px;\n font-size: 13px;\n line-height: 1.42857143;\n word-break: break-all;\n word-wrap: break-word;\n color: #333333;\n background-color: #f5f5f5;\n border: 1px solid #cccccc;\n border-radius: 4px;\n}\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n}\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n.container {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n@media (min-width: 768px) {\n .container {\n width: 750px;\n }\n}\n@media (min-width: 992px) {\n .container {\n width: 970px;\n }\n}\n@media (min-width: 1200px) {\n .container {\n width: 1170px;\n }\n}\n.container-fluid {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n.row {\n margin-left: -15px;\n margin-right: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n position: relative;\n min-height: 1px;\n padding-left: 15px;\n padding-right: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n float: left;\n}\n.col-xs-12 {\n width: 100%;\n}\n.col-xs-11 {\n width: 91.66666667%;\n}\n.col-xs-10 {\n width: 83.33333333%;\n}\n.col-xs-9 {\n width: 75%;\n}\n.col-xs-8 {\n width: 66.66666667%;\n}\n.col-xs-7 {\n width: 58.33333333%;\n}\n.col-xs-6 {\n width: 50%;\n}\n.col-xs-5 {\n width: 41.66666667%;\n}\n.col-xs-4 {\n width: 33.33333333%;\n}\n.col-xs-3 {\n width: 25%;\n}\n.col-xs-2 {\n width: 16.66666667%;\n}\n.col-xs-1 {\n width: 8.33333333%;\n}\n.col-xs-pull-12 {\n right: 100%;\n}\n.col-xs-pull-11 {\n right: 91.66666667%;\n}\n.col-xs-pull-10 {\n right: 83.33333333%;\n}\n.col-xs-pull-9 {\n right: 75%;\n}\n.col-xs-pull-8 {\n right: 66.66666667%;\n}\n.col-xs-pull-7 {\n right: 58.33333333%;\n}\n.col-xs-pull-6 {\n right: 50%;\n}\n.col-xs-pull-5 {\n right: 41.66666667%;\n}\n.col-xs-pull-4 {\n right: 33.33333333%;\n}\n.col-xs-pull-3 {\n right: 25%;\n}\n.col-xs-pull-2 {\n right: 16.66666667%;\n}\n.col-xs-pull-1 {\n right: 8.33333333%;\n}\n.col-xs-pull-0 {\n right: auto;\n}\n.col-xs-push-12 {\n left: 100%;\n}\n.col-xs-push-11 {\n left: 91.66666667%;\n}\n.col-xs-push-10 {\n left: 83.33333333%;\n}\n.col-xs-push-9 {\n left: 75%;\n}\n.col-xs-push-8 {\n left: 66.66666667%;\n}\n.col-xs-push-7 {\n left: 58.33333333%;\n}\n.col-xs-push-6 {\n left: 50%;\n}\n.col-xs-push-5 {\n left: 41.66666667%;\n}\n.col-xs-push-4 {\n left: 33.33333333%;\n}\n.col-xs-push-3 {\n left: 25%;\n}\n.col-xs-push-2 {\n left: 16.66666667%;\n}\n.col-xs-push-1 {\n left: 8.33333333%;\n}\n.col-xs-push-0 {\n left: auto;\n}\n.col-xs-offset-12 {\n margin-left: 100%;\n}\n.col-xs-offset-11 {\n margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n margin-left: 75%;\n}\n.col-xs-offset-8 {\n margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n margin-left: 50%;\n}\n.col-xs-offset-5 {\n margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n margin-left: 25%;\n}\n.col-xs-offset-2 {\n margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n margin-left: 0%;\n}\n@media (min-width: 768px) {\n .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\n float: left;\n }\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666667%;\n }\n .col-sm-10 {\n width: 83.33333333%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666667%;\n }\n .col-sm-7 {\n width: 58.33333333%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666667%;\n }\n .col-sm-4 {\n width: 33.33333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.66666667%;\n }\n .col-sm-1 {\n width: 8.33333333%;\n }\n .col-sm-pull-12 {\n right: 100%;\n }\n .col-sm-pull-11 {\n right: 91.66666667%;\n }\n .col-sm-pull-10 {\n right: 83.33333333%;\n }\n .col-sm-pull-9 {\n right: 75%;\n }\n .col-sm-pull-8 {\n right: 66.66666667%;\n }\n .col-sm-pull-7 {\n right: 58.33333333%;\n }\n .col-sm-pull-6 {\n right: 50%;\n }\n .col-sm-pull-5 {\n right: 41.66666667%;\n }\n .col-sm-pull-4 {\n right: 33.33333333%;\n }\n .col-sm-pull-3 {\n right: 25%;\n }\n .col-sm-pull-2 {\n right: 16.66666667%;\n }\n .col-sm-pull-1 {\n right: 8.33333333%;\n }\n .col-sm-pull-0 {\n right: auto;\n }\n .col-sm-push-12 {\n left: 100%;\n }\n .col-sm-push-11 {\n left: 91.66666667%;\n }\n .col-sm-push-10 {\n left: 83.33333333%;\n }\n .col-sm-push-9 {\n left: 75%;\n }\n .col-sm-push-8 {\n left: 66.66666667%;\n }\n .col-sm-push-7 {\n left: 58.33333333%;\n }\n .col-sm-push-6 {\n left: 50%;\n }\n .col-sm-push-5 {\n left: 41.66666667%;\n }\n .col-sm-push-4 {\n left: 33.33333333%;\n }\n .col-sm-push-3 {\n left: 25%;\n }\n .col-sm-push-2 {\n left: 16.66666667%;\n }\n .col-sm-push-1 {\n left: 8.33333333%;\n }\n .col-sm-push-0 {\n left: auto;\n }\n .col-sm-offset-12 {\n margin-left: 100%;\n }\n .col-sm-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-sm-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-sm-offset-9 {\n margin-left: 75%;\n }\n .col-sm-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-sm-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-sm-offset-6 {\n margin-left: 50%;\n }\n .col-sm-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-sm-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-sm-offset-3 {\n margin-left: 25%;\n }\n .col-sm-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-sm-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-sm-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 992px) {\n .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\n float: left;\n }\n .col-md-12 {\n width: 100%;\n }\n .col-md-11 {\n width: 91.66666667%;\n }\n .col-md-10 {\n width: 83.33333333%;\n }\n .col-md-9 {\n width: 75%;\n }\n .col-md-8 {\n width: 66.66666667%;\n }\n .col-md-7 {\n width: 58.33333333%;\n }\n .col-md-6 {\n width: 50%;\n }\n .col-md-5 {\n width: 41.66666667%;\n }\n .col-md-4 {\n width: 33.33333333%;\n }\n .col-md-3 {\n width: 25%;\n }\n .col-md-2 {\n width: 16.66666667%;\n }\n .col-md-1 {\n width: 8.33333333%;\n }\n .col-md-pull-12 {\n right: 100%;\n }\n .col-md-pull-11 {\n right: 91.66666667%;\n }\n .col-md-pull-10 {\n right: 83.33333333%;\n }\n .col-md-pull-9 {\n right: 75%;\n }\n .col-md-pull-8 {\n right: 66.66666667%;\n }\n .col-md-pull-7 {\n right: 58.33333333%;\n }\n .col-md-pull-6 {\n right: 50%;\n }\n .col-md-pull-5 {\n right: 41.66666667%;\n }\n .col-md-pull-4 {\n right: 33.33333333%;\n }\n .col-md-pull-3 {\n right: 25%;\n }\n .col-md-pull-2 {\n right: 16.66666667%;\n }\n .col-md-pull-1 {\n right: 8.33333333%;\n }\n .col-md-pull-0 {\n right: auto;\n }\n .col-md-push-12 {\n left: 100%;\n }\n .col-md-push-11 {\n left: 91.66666667%;\n }\n .col-md-push-10 {\n left: 83.33333333%;\n }\n .col-md-push-9 {\n left: 75%;\n }\n .col-md-push-8 {\n left: 66.66666667%;\n }\n .col-md-push-7 {\n left: 58.33333333%;\n }\n .col-md-push-6 {\n left: 50%;\n }\n .col-md-push-5 {\n left: 41.66666667%;\n }\n .col-md-push-4 {\n left: 33.33333333%;\n }\n .col-md-push-3 {\n left: 25%;\n }\n .col-md-push-2 {\n left: 16.66666667%;\n }\n .col-md-push-1 {\n left: 8.33333333%;\n }\n .col-md-push-0 {\n left: auto;\n }\n .col-md-offset-12 {\n margin-left: 100%;\n }\n .col-md-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-md-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-md-offset-9 {\n margin-left: 75%;\n }\n .col-md-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-md-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-md-offset-6 {\n margin-left: 50%;\n }\n .col-md-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-md-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-md-offset-3 {\n margin-left: 25%;\n }\n .col-md-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-md-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-md-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 1200px) {\n .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\n float: left;\n }\n .col-lg-12 {\n width: 100%;\n }\n .col-lg-11 {\n width: 91.66666667%;\n }\n .col-lg-10 {\n width: 83.33333333%;\n }\n .col-lg-9 {\n width: 75%;\n }\n .col-lg-8 {\n width: 66.66666667%;\n }\n .col-lg-7 {\n width: 58.33333333%;\n }\n .col-lg-6 {\n width: 50%;\n }\n .col-lg-5 {\n width: 41.66666667%;\n }\n .col-lg-4 {\n width: 33.33333333%;\n }\n .col-lg-3 {\n width: 25%;\n }\n .col-lg-2 {\n width: 16.66666667%;\n }\n .col-lg-1 {\n width: 8.33333333%;\n }\n .col-lg-pull-12 {\n right: 100%;\n }\n .col-lg-pull-11 {\n right: 91.66666667%;\n }\n .col-lg-pull-10 {\n right: 83.33333333%;\n }\n .col-lg-pull-9 {\n right: 75%;\n }\n .col-lg-pull-8 {\n right: 66.66666667%;\n }\n .col-lg-pull-7 {\n right: 58.33333333%;\n }\n .col-lg-pull-6 {\n right: 50%;\n }\n .col-lg-pull-5 {\n right: 41.66666667%;\n }\n .col-lg-pull-4 {\n right: 33.33333333%;\n }\n .col-lg-pull-3 {\n right: 25%;\n }\n .col-lg-pull-2 {\n right: 16.66666667%;\n }\n .col-lg-pull-1 {\n right: 8.33333333%;\n }\n .col-lg-pull-0 {\n right: auto;\n }\n .col-lg-push-12 {\n left: 100%;\n }\n .col-lg-push-11 {\n left: 91.66666667%;\n }\n .col-lg-push-10 {\n left: 83.33333333%;\n }\n .col-lg-push-9 {\n left: 75%;\n }\n .col-lg-push-8 {\n left: 66.66666667%;\n }\n .col-lg-push-7 {\n left: 58.33333333%;\n }\n .col-lg-push-6 {\n left: 50%;\n }\n .col-lg-push-5 {\n left: 41.66666667%;\n }\n .col-lg-push-4 {\n left: 33.33333333%;\n }\n .col-lg-push-3 {\n left: 25%;\n }\n .col-lg-push-2 {\n left: 16.66666667%;\n }\n .col-lg-push-1 {\n left: 8.33333333%;\n }\n .col-lg-push-0 {\n left: auto;\n }\n .col-lg-offset-12 {\n margin-left: 100%;\n }\n .col-lg-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-lg-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-lg-offset-9 {\n margin-left: 75%;\n }\n .col-lg-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-lg-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-lg-offset-6 {\n margin-left: 50%;\n }\n .col-lg-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-lg-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-lg-offset-3 {\n margin-left: 25%;\n }\n .col-lg-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-lg-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-lg-offset-0 {\n margin-left: 0%;\n }\n}\ntable {\n background-color: transparent;\n}\ncaption {\n padding-top: 8px;\n padding-bottom: 8px;\n color: #777777;\n text-align: left;\n}\nth {\n text-align: left;\n}\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n padding: 8px;\n line-height: 1.42857143;\n vertical-align: top;\n border-top: 1px solid #dddddd;\n}\n.table > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid #dddddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n border-top: 0;\n}\n.table > tbody + tbody {\n border-top: 2px solid #dddddd;\n}\n.table .table {\n background-color: #ffffff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n padding: 5px;\n}\n.table-bordered {\n border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-column;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-cell;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n background-color: #ebcccc;\n}\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%;\n}\n@media screen and (max-width: 767px) {\n .table-responsive {\n width: 100%;\n margin-bottom: 15px;\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid #dddddd;\n }\n .table-responsive > .table {\n margin-bottom: 0;\n }\n .table-responsive > .table > thead > tr > th,\n .table-responsive > .table > tbody > tr > th,\n .table-responsive > .table > tfoot > tr > th,\n .table-responsive > .table > thead > tr > td,\n .table-responsive > .table > tbody > tr > td,\n .table-responsive > .table > tfoot > tr > td {\n white-space: nowrap;\n }\n .table-responsive > .table-bordered {\n border: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:first-child,\n .table-responsive > .table-bordered > tbody > tr > th:first-child,\n .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n .table-responsive > .table-bordered > thead > tr > td:first-child,\n .table-responsive > .table-bordered > tbody > tr > td:first-child,\n .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:last-child,\n .table-responsive > .table-bordered > tbody > tr > th:last-child,\n .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n .table-responsive > .table-bordered > thead > tr > td:last-child,\n .table-responsive > .table-bordered > tbody > tr > td:last-child,\n .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n }\n .table-responsive > .table-bordered > tbody > tr:last-child > th,\n .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n .table-responsive > .table-bordered > tbody > tr:last-child > td,\n .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n border-bottom: 0;\n }\n}\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n min-width: 0;\n}\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: 20px;\n font-size: 21px;\n line-height: inherit;\n color: #333333;\n border: 0;\n border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n display: inline-block;\n max-width: 100%;\n margin-bottom: 5px;\n font-weight: bold;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9;\n line-height: normal;\n}\ninput[type=\"file\"] {\n display: block;\n}\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\nselect[multiple],\nselect[size] {\n height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\noutput {\n display: block;\n padding-top: 7px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n}\n.form-control {\n display: block;\n width: 100%;\n height: 34px;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n background-color: #ffffff;\n background-image: none;\n border: 1px solid #cccccc;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n border-color: #66afe9;\n outline: 0;\n -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n color: #999999;\n opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n color: #999999;\n}\n.form-control::-webkit-input-placeholder {\n color: #999999;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n background-color: #eeeeee;\n opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n cursor: not-allowed;\n}\ntextarea.form-control {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"].form-control,\n input[type=\"time\"].form-control,\n input[type=\"datetime-local\"].form-control,\n input[type=\"month\"].form-control {\n line-height: 34px;\n }\n input[type=\"date\"].input-sm,\n input[type=\"time\"].input-sm,\n input[type=\"datetime-local\"].input-sm,\n input[type=\"month\"].input-sm,\n .input-group-sm input[type=\"date\"],\n .input-group-sm input[type=\"time\"],\n .input-group-sm input[type=\"datetime-local\"],\n .input-group-sm input[type=\"month\"] {\n line-height: 30px;\n }\n input[type=\"date\"].input-lg,\n input[type=\"time\"].input-lg,\n input[type=\"datetime-local\"].input-lg,\n input[type=\"month\"].input-lg,\n .input-group-lg input[type=\"date\"],\n .input-group-lg input[type=\"time\"],\n .input-group-lg input[type=\"datetime-local\"],\n .input-group-lg input[type=\"month\"] {\n line-height: 46px;\n }\n}\n.form-group {\n margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n min-height: 20px;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-left: -20px;\n margin-top: 4px \\9;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n cursor: not-allowed;\n}\n.form-control-static {\n padding-top: 7px;\n padding-bottom: 7px;\n margin-bottom: 0;\n min-height: 34px;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n padding-left: 0;\n padding-right: 0;\n}\n.input-sm {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-sm {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n height: auto;\n}\n.form-group-sm .form-control {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.form-group-sm select.form-control {\n height: 30px;\n line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n height: auto;\n}\n.form-group-sm .form-control-static {\n height: 30px;\n min-height: 32px;\n padding: 6px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.input-lg {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-lg {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n height: auto;\n}\n.form-group-lg .form-control {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.form-group-lg select.form-control {\n height: 46px;\n line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n height: auto;\n}\n.form-group-lg .form-control-static {\n height: 46px;\n min-height: 38px;\n padding: 11px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.has-feedback {\n position: relative;\n}\n.has-feedback .form-control {\n padding-right: 42.5px;\n}\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: 46px;\n height: 46px;\n line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: 30px;\n height: 30px;\n line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n color: #3c763d;\n}\n.has-success .form-control {\n border-color: #3c763d;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n border-color: #2b542c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n color: #3c763d;\n border-color: #3c763d;\n background-color: #dff0d8;\n}\n.has-success .form-control-feedback {\n color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n color: #8a6d3b;\n}\n.has-warning .form-control {\n border-color: #8a6d3b;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n border-color: #66512c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n color: #8a6d3b;\n border-color: #8a6d3b;\n background-color: #fcf8e3;\n}\n.has-warning .form-control-feedback {\n color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n color: #a94442;\n}\n.has-error .form-control {\n border-color: #a94442;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n border-color: #843534;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n color: #a94442;\n border-color: #a94442;\n background-color: #f2dede;\n}\n.has-error .form-control-feedback {\n color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n top: 0;\n}\n.help-block {\n display: block;\n margin-top: 5px;\n margin-bottom: 10px;\n color: #737373;\n}\n@media (min-width: 768px) {\n .form-inline .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-static {\n display: inline-block;\n }\n .form-inline .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .form-inline .input-group .input-group-addon,\n .form-inline .input-group .input-group-btn,\n .form-inline .input-group .form-control {\n width: auto;\n }\n .form-inline .input-group > .form-control {\n width: 100%;\n }\n .form-inline .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio,\n .form-inline .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio label,\n .form-inline .checkbox label {\n padding-left: 0;\n }\n .form-inline .radio input[type=\"radio\"],\n .form-inline .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: 7px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n min-height: 27px;\n}\n.form-horizontal .form-group {\n margin-left: -15px;\n margin-right: -15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .control-label {\n text-align: right;\n margin-bottom: 0;\n padding-top: 7px;\n }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n right: 15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-lg .control-label {\n padding-top: 14.333333px;\n font-size: 18px;\n }\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-sm .control-label {\n padding-top: 6px;\n font-size: 12px;\n }\n}\n.btn {\n display: inline-block;\n margin-bottom: 0;\n font-weight: normal;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none;\n border: 1px solid transparent;\n white-space: nowrap;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n border-radius: 4px;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n color: #333333;\n text-decoration: none;\n}\n.btn:active,\n.btn.active {\n outline: 0;\n background-image: none;\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n cursor: not-allowed;\n opacity: 0.65;\n filter: alpha(opacity=65);\n -webkit-box-shadow: none;\n box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n pointer-events: none;\n}\n.btn-default {\n color: #333333;\n background-color: #ffffff;\n border-color: #cccccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n color: #333333;\n background-color: #e6e6e6;\n border-color: #8c8c8c;\n}\n.btn-default:hover {\n color: #333333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n color: #333333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n color: #333333;\n background-color: #d4d4d4;\n border-color: #8c8c8c;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n background-image: none;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n background-color: #ffffff;\n border-color: #cccccc;\n}\n.btn-default .badge {\n color: #ffffff;\n background-color: #333333;\n}\n.btn-primary {\n color: #ffffff;\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n color: #ffffff;\n background-color: #286090;\n border-color: #122b40;\n}\n.btn-primary:hover {\n color: #ffffff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n color: #ffffff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n color: #ffffff;\n background-color: #204d74;\n border-color: #122b40;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n background-image: none;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary .badge {\n color: #337ab7;\n background-color: #ffffff;\n}\n.btn-success {\n color: #ffffff;\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n color: #ffffff;\n background-color: #449d44;\n border-color: #255625;\n}\n.btn-success:hover {\n color: #ffffff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n color: #ffffff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n color: #ffffff;\n background-color: #398439;\n border-color: #255625;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n background-image: none;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success .badge {\n color: #5cb85c;\n background-color: #ffffff;\n}\n.btn-info {\n color: #ffffff;\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n color: #ffffff;\n background-color: #31b0d5;\n border-color: #1b6d85;\n}\n.btn-info:hover {\n color: #ffffff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n color: #ffffff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n color: #ffffff;\n background-color: #269abc;\n border-color: #1b6d85;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n background-image: none;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info .badge {\n color: #5bc0de;\n background-color: #ffffff;\n}\n.btn-warning {\n color: #ffffff;\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n color: #ffffff;\n background-color: #ec971f;\n border-color: #985f0d;\n}\n.btn-warning:hover {\n color: #ffffff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n color: #ffffff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n color: #ffffff;\n background-color: #d58512;\n border-color: #985f0d;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n background-image: none;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning .badge {\n color: #f0ad4e;\n background-color: #ffffff;\n}\n.btn-danger {\n color: #ffffff;\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n color: #ffffff;\n background-color: #c9302c;\n border-color: #761c19;\n}\n.btn-danger:hover {\n color: #ffffff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n color: #ffffff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n color: #ffffff;\n background-color: #ac2925;\n border-color: #761c19;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n background-image: none;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger .badge {\n color: #d9534f;\n background-color: #ffffff;\n}\n.btn-link {\n color: #337ab7;\n font-weight: normal;\n border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n background-color: transparent;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n color: #23527c;\n text-decoration: underline;\n background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n color: #777777;\n text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n padding: 1px 5px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-block {\n display: block;\n width: 100%;\n}\n.btn-block + .btn-block {\n margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n.fade {\n opacity: 0;\n -webkit-transition: opacity 0.15s linear;\n -o-transition: opacity 0.15s linear;\n transition: opacity 0.15s linear;\n}\n.fade.in {\n opacity: 1;\n}\n.collapse {\n display: none;\n}\n.collapse.in {\n display: block;\n}\ntr.collapse.in {\n display: table-row;\n}\ntbody.collapse.in {\n display: table-row-group;\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n -webkit-transition-property: height, visibility;\n transition-property: height, visibility;\n -webkit-transition-duration: 0.35s;\n transition-duration: 0.35s;\n -webkit-transition-timing-function: ease;\n transition-timing-function: ease;\n}\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: 4px dashed;\n border-top: 4px solid \\9;\n border-right: 4px solid transparent;\n border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n position: relative;\n}\n.dropdown-toggle:focus {\n outline: 0;\n}\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0;\n list-style: none;\n font-size: 14px;\n text-align: left;\n background-color: #ffffff;\n border: 1px solid #cccccc;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 4px;\n -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n background-clip: padding-box;\n}\n.dropdown-menu.pull-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu .divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: 1.42857143;\n color: #333333;\n white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n text-decoration: none;\n color: #262626;\n background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n color: #ffffff;\n text-decoration: none;\n outline: 0;\n background-color: #337ab7;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n cursor: not-allowed;\n}\n.open > .dropdown-menu {\n display: block;\n}\n.open > a {\n outline: 0;\n}\n.dropdown-menu-right {\n left: auto;\n right: 0;\n}\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: 12px;\n line-height: 1.42857143;\n color: #777777;\n white-space: nowrap;\n}\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: 990;\n}\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n border-top: 0;\n border-bottom: 4px dashed;\n border-bottom: 4px solid \\9;\n content: \"\";\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n .navbar-right .dropdown-menu {\n left: auto;\n right: 0;\n }\n .navbar-right .dropdown-menu-left {\n left: 0;\n right: auto;\n }\n}\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n margin-left: -1px;\n}\n.btn-toolbar {\n margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n.btn-group.open .dropdown-toggle {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn .caret {\n margin-left: 0;\n}\n.btn-lg .caret {\n border-width: 5px 5px 0;\n border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-bottom-left-radius: 4px;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.input-group {\n position: relative;\n display: table;\n border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n}\n.input-group .form-control {\n position: relative;\n z-index: 2;\n float: left;\n width: 100%;\n margin-bottom: 0;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle;\n}\n.input-group-addon {\n padding: 6px 12px;\n font-size: 14px;\n font-weight: normal;\n line-height: 1;\n color: #555555;\n text-align: center;\n background-color: #eeeeee;\n border: 1px solid #cccccc;\n border-radius: 4px;\n}\n.input-group-addon.input-sm {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 3px;\n}\n.input-group-addon.input-lg {\n padding: 10px 16px;\n font-size: 18px;\n border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n.input-group-btn > .btn {\n position: relative;\n}\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n z-index: 2;\n margin-left: -1px;\n}\n.nav {\n margin-bottom: 0;\n padding-left: 0;\n list-style: none;\n}\n.nav > li {\n position: relative;\n display: block;\n}\n.nav > li > a {\n position: relative;\n display: block;\n padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n color: #777777;\n text-decoration: none;\n background-color: transparent;\n cursor: not-allowed;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n background-color: #eeeeee;\n border-color: #337ab7;\n}\n.nav .nav-divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.nav > li > a > img {\n max-width: none;\n}\n.nav-tabs {\n border-bottom: 1px solid #dddddd;\n}\n.nav-tabs > li {\n float: left;\n margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n margin-right: 2px;\n line-height: 1.42857143;\n border: 1px solid transparent;\n border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n border-color: #eeeeee #eeeeee #dddddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n color: #555555;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-bottom-color: transparent;\n cursor: default;\n}\n.nav-tabs.nav-justified {\n width: 100%;\n border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n float: none;\n}\n.nav-tabs.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-tabs.nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs.nav-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li > a {\n border-bottom: 1px solid #dddddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs.nav-justified > .active > a,\n .nav-tabs.nav-justified > .active > a:hover,\n .nav-tabs.nav-justified > .active > a:focus {\n border-bottom-color: #ffffff;\n }\n}\n.nav-pills > li {\n float: left;\n}\n.nav-pills > li > a {\n border-radius: 4px;\n}\n.nav-pills > li + li {\n margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n color: #ffffff;\n background-color: #337ab7;\n}\n.nav-stacked > li {\n float: none;\n}\n.nav-stacked > li + li {\n margin-top: 2px;\n margin-left: 0;\n}\n.nav-justified {\n width: 100%;\n}\n.nav-justified > li {\n float: none;\n}\n.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs-justified {\n border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n .nav-tabs-justified > li > a {\n border-bottom: 1px solid #dddddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs-justified > .active > a,\n .nav-tabs-justified > .active > a:hover,\n .nav-tabs-justified > .active > a:focus {\n border-bottom-color: #ffffff;\n }\n}\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar {\n position: relative;\n min-height: 50px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n .navbar {\n border-radius: 4px;\n }\n}\n@media (min-width: 768px) {\n .navbar-header {\n float: left;\n }\n}\n.navbar-collapse {\n overflow-x: visible;\n padding-right: 15px;\n padding-left: 15px;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n overflow-y: auto;\n}\n@media (min-width: 768px) {\n .navbar-collapse {\n width: auto;\n border-top: 0;\n box-shadow: none;\n }\n .navbar-collapse.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0;\n overflow: visible !important;\n }\n .navbar-collapse.in {\n overflow-y: visible;\n }\n .navbar-fixed-top .navbar-collapse,\n .navbar-static-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n padding-left: 0;\n padding-right: 0;\n }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n .navbar-fixed-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n max-height: 200px;\n }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .container > .navbar-header,\n .container-fluid > .navbar-header,\n .container > .navbar-collapse,\n .container-fluid > .navbar-collapse {\n margin-right: 0;\n margin-left: 0;\n }\n}\n.navbar-static-top {\n z-index: 1000;\n border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n .navbar-static-top {\n border-radius: 0;\n }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n@media (min-width: 768px) {\n .navbar-fixed-top,\n .navbar-fixed-bottom {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0;\n border-width: 1px 0 0;\n}\n.navbar-brand {\n float: left;\n padding: 15px 15px;\n font-size: 18px;\n line-height: 20px;\n height: 50px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n text-decoration: none;\n}\n.navbar-brand > img {\n display: block;\n}\n@media (min-width: 768px) {\n .navbar > .container .navbar-brand,\n .navbar > .container-fluid .navbar-brand {\n margin-left: -15px;\n }\n}\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: 15px;\n padding: 9px 10px;\n margin-top: 8px;\n margin-bottom: 8px;\n background-color: transparent;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.navbar-toggle:focus {\n outline: 0;\n}\n.navbar-toggle .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n margin-top: 4px;\n}\n@media (min-width: 768px) {\n .navbar-toggle {\n display: none;\n }\n}\n.navbar-nav {\n margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: 20px;\n}\n@media (max-width: 767px) {\n .navbar-nav .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n }\n .navbar-nav .open .dropdown-menu > li > a,\n .navbar-nav .open .dropdown-menu .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n .navbar-nav .open .dropdown-menu > li > a {\n line-height: 20px;\n }\n .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-nav .open .dropdown-menu > li > a:focus {\n background-image: none;\n }\n}\n@media (min-width: 768px) {\n .navbar-nav {\n float: left;\n margin: 0;\n }\n .navbar-nav > li {\n float: left;\n }\n .navbar-nav > li > a {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n}\n.navbar-form {\n margin-left: -15px;\n margin-right: -15px;\n padding: 10px 15px;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n margin-top: 8px;\n margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n .navbar-form .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .navbar-form .form-control-static {\n display: inline-block;\n }\n .navbar-form .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .navbar-form .input-group .input-group-addon,\n .navbar-form .input-group .input-group-btn,\n .navbar-form .input-group .form-control {\n width: auto;\n }\n .navbar-form .input-group > .form-control {\n width: 100%;\n }\n .navbar-form .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio,\n .navbar-form .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio label,\n .navbar-form .checkbox label {\n padding-left: 0;\n }\n .navbar-form .radio input[type=\"radio\"],\n .navbar-form .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .navbar-form .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n@media (max-width: 767px) {\n .navbar-form .form-group {\n margin-bottom: 5px;\n }\n .navbar-form .form-group:last-child {\n margin-bottom: 0;\n }\n}\n@media (min-width: 768px) {\n .navbar-form {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n}\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.navbar-btn {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n margin-top: 14px;\n margin-bottom: 14px;\n}\n.navbar-text {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n .navbar-text {\n float: left;\n margin-left: 15px;\n margin-right: 15px;\n }\n}\n@media (min-width: 768px) {\n .navbar-left {\n float: left !important;\n }\n .navbar-right {\n float: right !important;\n margin-right: -15px;\n }\n .navbar-right ~ .navbar-right {\n margin-right: 0;\n }\n}\n.navbar-default {\n background-color: #f8f8f8;\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n color: #777777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n color: #5e5e5e;\n background-color: transparent;\n}\n.navbar-default .navbar-text {\n color: #777777;\n}\n.navbar-default .navbar-nav > li > a {\n color: #777777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n color: #333333;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n color: #555555;\n background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n color: #cccccc;\n background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n border-color: #dddddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n background-color: #dddddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n background-color: #888888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n background-color: #e7e7e7;\n color: #555555;\n}\n@media (max-width: 767px) {\n .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n color: #777777;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #333333;\n background-color: transparent;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #555555;\n background-color: #e7e7e7;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #cccccc;\n background-color: transparent;\n }\n}\n.navbar-default .navbar-link {\n color: #777777;\n}\n.navbar-default .navbar-link:hover {\n color: #333333;\n}\n.navbar-default .btn-link {\n color: #777777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n color: #333333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n color: #cccccc;\n}\n.navbar-inverse {\n background-color: #222222;\n border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n color: #ffffff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n color: #ffffff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n color: #ffffff;\n background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n color: #444444;\n background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n border-color: #333333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n background-color: #333333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n background-color: #ffffff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n background-color: #080808;\n color: #ffffff;\n}\n@media (max-width: 767px) {\n .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n border-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n color: #9d9d9d;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #ffffff;\n background-color: transparent;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #ffffff;\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #444444;\n background-color: transparent;\n }\n}\n.navbar-inverse .navbar-link {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n color: #ffffff;\n}\n.navbar-inverse .btn-link {\n color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n color: #ffffff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n color: #444444;\n}\n.breadcrumb {\n padding: 8px 15px;\n margin-bottom: 20px;\n list-style: none;\n background-color: #f5f5f5;\n border-radius: 4px;\n}\n.breadcrumb > li {\n display: inline-block;\n}\n.breadcrumb > li + li:before {\n content: \"/\\00a0\";\n padding: 0 5px;\n color: #cccccc;\n}\n.breadcrumb > .active {\n color: #777777;\n}\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: 20px 0;\n border-radius: 4px;\n}\n.pagination > li {\n display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n position: relative;\n float: left;\n padding: 6px 12px;\n line-height: 1.42857143;\n text-decoration: none;\n color: #337ab7;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n margin-left: -1px;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n margin-left: 0;\n border-bottom-left-radius: 4px;\n border-top-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n border-bottom-right-radius: 4px;\n border-top-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n z-index: 3;\n color: #23527c;\n background-color: #eeeeee;\n border-color: #dddddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n z-index: 2;\n color: #ffffff;\n background-color: #337ab7;\n border-color: #337ab7;\n cursor: default;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n color: #777777;\n background-color: #ffffff;\n border-color: #dddddd;\n cursor: not-allowed;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n border-bottom-left-radius: 6px;\n border-top-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n border-bottom-right-radius: 6px;\n border-top-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n border-bottom-left-radius: 3px;\n border-top-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n border-bottom-right-radius: 3px;\n border-top-right-radius: 3px;\n}\n.pager {\n padding-left: 0;\n margin: 20px 0;\n list-style: none;\n text-align: center;\n}\n.pager li {\n display: inline;\n}\n.pager li > a,\n.pager li > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n color: #777777;\n background-color: #ffffff;\n cursor: not-allowed;\n}\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: #ffffff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n color: #ffffff;\n text-decoration: none;\n cursor: pointer;\n}\n.label:empty {\n display: none;\n}\n.btn .label {\n position: relative;\n top: -1px;\n}\n.label-default {\n background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n background-color: #5e5e5e;\n}\n.label-primary {\n background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n background-color: #286090;\n}\n.label-success {\n background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n background-color: #449d44;\n}\n.label-info {\n background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n background-color: #31b0d5;\n}\n.label-warning {\n background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n background-color: #ec971f;\n}\n.label-danger {\n background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n background-color: #c9302c;\n}\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: 12px;\n font-weight: bold;\n color: #ffffff;\n line-height: 1;\n vertical-align: middle;\n white-space: nowrap;\n text-align: center;\n background-color: #777777;\n border-radius: 10px;\n}\n.badge:empty {\n display: none;\n}\n.btn .badge {\n position: relative;\n top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n top: 0;\n padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n color: #ffffff;\n text-decoration: none;\n cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: #337ab7;\n background-color: #ffffff;\n}\n.list-group-item > .badge {\n float: right;\n}\n.list-group-item > .badge + .badge {\n margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n.jumbotron {\n padding-top: 30px;\n padding-bottom: 30px;\n margin-bottom: 30px;\n color: inherit;\n background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n color: inherit;\n}\n.jumbotron p {\n margin-bottom: 15px;\n font-size: 21px;\n font-weight: 200;\n}\n.jumbotron > hr {\n border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n border-radius: 6px;\n}\n.jumbotron .container {\n max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n .jumbotron {\n padding-top: 48px;\n padding-bottom: 48px;\n }\n .container .jumbotron,\n .container-fluid .jumbotron {\n padding-left: 60px;\n padding-right: 60px;\n }\n .jumbotron h1,\n .jumbotron .h1 {\n font-size: 63px;\n }\n}\n.thumbnail {\n display: block;\n padding: 4px;\n margin-bottom: 20px;\n line-height: 1.42857143;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 4px;\n -webkit-transition: border 0.2s ease-in-out;\n -o-transition: border 0.2s ease-in-out;\n transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n margin-left: auto;\n margin-right: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n border-color: #337ab7;\n}\n.thumbnail .caption {\n padding: 9px;\n color: #333333;\n}\n.alert {\n padding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.alert h4 {\n margin-top: 0;\n color: inherit;\n}\n.alert .alert-link {\n font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n margin-bottom: 0;\n}\n.alert > p + p {\n margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n}\n.alert-success {\n background-color: #dff0d8;\n border-color: #d6e9c6;\n color: #3c763d;\n}\n.alert-success hr {\n border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n color: #2b542c;\n}\n.alert-info {\n background-color: #d9edf7;\n border-color: #bce8f1;\n color: #31708f;\n}\n.alert-info hr {\n border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n color: #245269;\n}\n.alert-warning {\n background-color: #fcf8e3;\n border-color: #faebcc;\n color: #8a6d3b;\n}\n.alert-warning hr {\n border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n color: #66512c;\n}\n.alert-danger {\n background-color: #f2dede;\n border-color: #ebccd1;\n color: #a94442;\n}\n.alert-danger hr {\n border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n.progress {\n overflow: hidden;\n height: 20px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: 12px;\n line-height: 20px;\n color: #ffffff;\n text-align: center;\n background-color: #337ab7;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n -webkit-transition: width 0.6s ease;\n -o-transition: width 0.6s ease;\n transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n -webkit-animation: progress-bar-stripes 2s linear infinite;\n -o-animation: progress-bar-stripes 2s linear infinite;\n animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n.media,\n.media-body {\n zoom: 1;\n overflow: hidden;\n}\n.media-body {\n width: 10000px;\n}\n.media-object {\n display: block;\n}\n.media-object.img-thumbnail {\n max-width: none;\n}\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n.media-middle {\n vertical-align: middle;\n}\n.media-bottom {\n vertical-align: bottom;\n}\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n.list-group {\n margin-bottom: 20px;\n padding-left: 0;\n}\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n margin-bottom: -1px;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n}\n.list-group-item:first-child {\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n}\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\na.list-group-item,\nbutton.list-group-item {\n color: #555555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n color: #333333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n text-decoration: none;\n color: #555555;\n background-color: #f5f5f5;\n}\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n background-color: #eeeeee;\n color: #777777;\n cursor: not-allowed;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n z-index: 2;\n color: #ffffff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n color: #c7ddef;\n}\n.list-group-item-success {\n color: #3c763d;\n background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n color: #3c763d;\n background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n color: #fff;\n background-color: #3c763d;\n border-color: #3c763d;\n}\n.list-group-item-info {\n color: #31708f;\n background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n color: #31708f;\n background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n color: #fff;\n background-color: #31708f;\n border-color: #31708f;\n}\n.list-group-item-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n color: #8a6d3b;\n background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n color: #fff;\n background-color: #8a6d3b;\n border-color: #8a6d3b;\n}\n.list-group-item-danger {\n color: #a94442;\n background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n color: #a94442;\n background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n color: #fff;\n background-color: #a94442;\n border-color: #a94442;\n}\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n.panel {\n margin-bottom: 20px;\n background-color: #ffffff;\n border: 1px solid transparent;\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n padding: 15px;\n}\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n color: inherit;\n}\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: 16px;\n color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n color: inherit;\n}\n.panel-footer {\n padding: 10px 15px;\n background-color: #f5f5f5;\n border-top: 1px solid #dddddd;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n border-top: 0;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n border-bottom: 0;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n border-top-width: 0;\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n padding-left: 15px;\n padding-right: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n border-bottom-left-radius: 3px;\n border-bottom-right-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n border-top: 1px solid #dddddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n border-bottom: 0;\n}\n.panel > .table-responsive {\n border: 0;\n margin-bottom: 0;\n}\n.panel-group {\n margin-bottom: 20px;\n}\n.panel-group .panel {\n margin-bottom: 0;\n border-radius: 4px;\n}\n.panel-group .panel + .panel {\n margin-top: 5px;\n}\n.panel-group .panel-heading {\n border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n border-top: 1px solid #dddddd;\n}\n.panel-group .panel-footer {\n border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n border-bottom: 1px solid #dddddd;\n}\n.panel-default {\n border-color: #dddddd;\n}\n.panel-default > .panel-heading {\n color: #333333;\n background-color: #f5f5f5;\n border-color: #dddddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #dddddd;\n}\n.panel-default > .panel-heading .badge {\n color: #f5f5f5;\n background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #dddddd;\n}\n.panel-primary {\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n color: #ffffff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n color: #337ab7;\n background-color: #ffffff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #337ab7;\n}\n.panel-success {\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n color: #dff0d8;\n background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #d6e9c6;\n}\n.panel-info {\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n color: #d9edf7;\n background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #bce8f1;\n}\n.panel-warning {\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n color: #fcf8e3;\n background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #faebcc;\n}\n.panel-danger {\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n color: #f2dede;\n background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n height: 100%;\n width: 100%;\n border: 0;\n}\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border: 1px solid #e3e3e3;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n padding: 24px;\n border-radius: 6px;\n}\n.well-sm {\n padding: 9px;\n border-radius: 3px;\n}\n.close {\n float: right;\n font-size: 21px;\n font-weight: bold;\n line-height: 1;\n color: #000000;\n text-shadow: 0 1px 0 #ffffff;\n opacity: 0.2;\n filter: alpha(opacity=20);\n}\n.close:hover,\n.close:focus {\n color: #000000;\n text-decoration: none;\n cursor: pointer;\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\nbutton.close {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n}\n.modal-open {\n overflow: hidden;\n}\n.modal {\n display: none;\n overflow: hidden;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1050;\n -webkit-overflow-scrolling: touch;\n outline: 0;\n}\n.modal.fade .modal-dialog {\n -webkit-transform: translate(0, -25%);\n -ms-transform: translate(0, -25%);\n -o-transform: translate(0, -25%);\n transform: translate(0, -25%);\n -webkit-transition: -webkit-transform 0.3s ease-out;\n -moz-transition: -moz-transform 0.3s ease-out;\n -o-transition: -o-transform 0.3s ease-out;\n transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n.modal-content {\n position: relative;\n background-color: #ffffff;\n border: 1px solid #999999;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n background-clip: padding-box;\n outline: 0;\n}\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n background-color: #000000;\n}\n.modal-backdrop.fade {\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #e5e5e5;\n min-height: 16.42857143px;\n}\n.modal-header .close {\n margin-top: -2px;\n}\n.modal-title {\n margin: 0;\n line-height: 1.42857143;\n}\n.modal-body {\n position: relative;\n padding: 15px;\n}\n.modal-footer {\n padding: 15px;\n text-align: right;\n border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0;\n}\n.modal-footer .btn-group .btn + .btn {\n margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n margin-left: 0;\n}\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n@media (min-width: 768px) {\n .modal-dialog {\n width: 600px;\n margin: 30px auto;\n }\n .modal-content {\n -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n }\n .modal-sm {\n width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg {\n width: 900px;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: 1.42857143;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n font-size: 12px;\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.tooltip.in {\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.tooltip.top {\n margin-top: -3px;\n padding: 5px 0;\n}\n.tooltip.right {\n margin-left: 3px;\n padding: 0 5px;\n}\n.tooltip.bottom {\n margin-top: 3px;\n padding: 5px 0;\n}\n.tooltip.left {\n margin-left: -3px;\n padding: 0 5px;\n}\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #ffffff;\n text-align: center;\n background-color: #000000;\n border-radius: 4px;\n}\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.top-left .tooltip-arrow {\n bottom: 0;\n right: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.top-right .tooltip-arrow {\n bottom: 0;\n left: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -5px;\n border-width: 5px 5px 5px 0;\n border-right-color: #000000;\n}\n.tooltip.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -5px;\n border-width: 5px 0 5px 5px;\n border-left-color: #000000;\n}\n.tooltip.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n top: 0;\n right: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n top: 0;\n left: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: none;\n max-width: 276px;\n padding: 1px;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: 1.42857143;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n font-size: 14px;\n background-color: #ffffff;\n background-clip: padding-box;\n border: 1px solid #cccccc;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n.popover.top {\n margin-top: -10px;\n}\n.popover.right {\n margin-left: 10px;\n}\n.popover.bottom {\n margin-top: 10px;\n}\n.popover.left {\n margin-left: -10px;\n}\n.popover-title {\n margin: 0;\n padding: 8px 14px;\n font-size: 14px;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-radius: 5px 5px 0 0;\n}\n.popover-content {\n padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover > .arrow {\n border-width: 11px;\n}\n.popover > .arrow:after {\n border-width: 10px;\n content: \"\";\n}\n.popover.top > .arrow {\n left: 50%;\n margin-left: -11px;\n border-bottom-width: 0;\n border-top-color: #999999;\n border-top-color: rgba(0, 0, 0, 0.25);\n bottom: -11px;\n}\n.popover.top > .arrow:after {\n content: \" \";\n bottom: 1px;\n margin-left: -10px;\n border-bottom-width: 0;\n border-top-color: #ffffff;\n}\n.popover.right > .arrow {\n top: 50%;\n left: -11px;\n margin-top: -11px;\n border-left-width: 0;\n border-right-color: #999999;\n border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right > .arrow:after {\n content: \" \";\n left: 1px;\n bottom: -10px;\n border-left-width: 0;\n border-right-color: #ffffff;\n}\n.popover.bottom > .arrow {\n left: 50%;\n margin-left: -11px;\n border-top-width: 0;\n border-bottom-color: #999999;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n top: -11px;\n}\n.popover.bottom > .arrow:after {\n content: \" \";\n top: 1px;\n margin-left: -10px;\n border-top-width: 0;\n border-bottom-color: #ffffff;\n}\n.popover.left > .arrow {\n top: 50%;\n right: -11px;\n margin-top: -11px;\n border-right-width: 0;\n border-left-color: #999999;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: #ffffff;\n bottom: -10px;\n}\n.carousel {\n position: relative;\n}\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n}\n.carousel-inner > .item {\n display: none;\n position: relative;\n -webkit-transition: 0.6s ease-in-out left;\n -o-transition: 0.6s ease-in-out left;\n transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n .carousel-inner > .item {\n -webkit-transition: -webkit-transform 0.6s ease-in-out;\n -moz-transition: -moz-transform 0.6s ease-in-out;\n -o-transition: -o-transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out;\n -webkit-backface-visibility: hidden;\n -moz-backface-visibility: hidden;\n backface-visibility: hidden;\n -webkit-perspective: 1000px;\n -moz-perspective: 1000px;\n perspective: 1000px;\n }\n .carousel-inner > .item.next,\n .carousel-inner > .item.active.right {\n -webkit-transform: translate3d(100%, 0, 0);\n transform: translate3d(100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.prev,\n .carousel-inner > .item.active.left {\n -webkit-transform: translate3d(-100%, 0, 0);\n transform: translate3d(-100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.next.left,\n .carousel-inner > .item.prev.right,\n .carousel-inner > .item.active {\n -webkit-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n left: 0;\n }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n display: block;\n}\n.carousel-inner > .active {\n left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n}\n.carousel-inner > .next {\n left: 100%;\n}\n.carousel-inner > .prev {\n left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n left: 0;\n}\n.carousel-inner > .active.left {\n left: -100%;\n}\n.carousel-inner > .active.right {\n left: 100%;\n}\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: 15%;\n opacity: 0.5;\n filter: alpha(opacity=50);\n font-size: 20px;\n color: #ffffff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-control.left {\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n left: auto;\n right: 0;\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n outline: 0;\n color: #ffffff;\n text-decoration: none;\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n margin-top: -10px;\n z-index: 5;\n display: inline-block;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n width: 20px;\n height: 20px;\n line-height: 1;\n font-family: serif;\n}\n.carousel-control .icon-prev:before {\n content: '\\2039';\n}\n.carousel-control .icon-next:before {\n content: '\\203a';\n}\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n}\n.carousel-indicators li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid #ffffff;\n border-radius: 10px;\n cursor: pointer;\n background-color: #000 \\9;\n background-color: rgba(0, 0, 0, 0);\n}\n.carousel-indicators .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: #ffffff;\n}\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #ffffff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-prev,\n .carousel-control .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -15px;\n font-size: 30px;\n }\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .icon-prev {\n margin-left: -15px;\n }\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-next {\n margin-right: -15px;\n }\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n .carousel-indicators {\n bottom: 20px;\n }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-footer:before,\n.modal-footer:after {\n content: \" \";\n display: table;\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-footer:after {\n clear: both;\n}\n.center-block {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n.hidden {\n display: none !important;\n}\n.affix {\n position: fixed;\n}\n@-ms-viewport {\n width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n@media (max-width: 767px) {\n .visible-xs {\n display: block !important;\n }\n table.visible-xs {\n display: table !important;\n }\n tr.visible-xs {\n display: table-row !important;\n }\n th.visible-xs,\n td.visible-xs {\n display: table-cell !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-block {\n display: block !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline {\n display: inline !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm {\n display: block !important;\n }\n table.visible-sm {\n display: table !important;\n }\n tr.visible-sm {\n display: table-row !important;\n }\n th.visible-sm,\n td.visible-sm {\n display: table-cell !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-block {\n display: block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline {\n display: inline !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md {\n display: block !important;\n }\n table.visible-md {\n display: table !important;\n }\n tr.visible-md {\n display: table-row !important;\n }\n th.visible-md,\n td.visible-md {\n display: table-cell !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-block {\n display: block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline {\n display: inline !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg {\n display: block !important;\n }\n table.visible-lg {\n display: table !important;\n }\n tr.visible-lg {\n display: table-row !important;\n }\n th.visible-lg,\n td.visible-lg {\n display: table-cell !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-block {\n display: block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline {\n display: inline !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline-block {\n display: inline-block !important;\n }\n}\n@media (max-width: 767px) {\n .hidden-xs {\n display: none !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .hidden-sm {\n display: none !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .hidden-md {\n display: none !important;\n }\n}\n@media (min-width: 1200px) {\n .hidden-lg {\n display: none !important;\n }\n}\n.visible-print {\n display: none !important;\n}\n@media print {\n .visible-print {\n display: block !important;\n }\n table.visible-print {\n display: table !important;\n }\n tr.visible-print {\n display: table-row !important;\n }\n th.visible-print,\n td.visible-print {\n display: table-cell !important;\n }\n}\n.visible-print-block {\n display: none !important;\n}\n@media print {\n .visible-print-block {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n}\n@media print {\n .visible-print-inline {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n}\n@media print {\n .visible-print-inline-block {\n display: inline-block !important;\n }\n}\n@media print {\n .hidden-print {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */","/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS and IE text size adjust after device orientation change,\n// without disabling user zoom.\n//\n\nhtml {\n font-family: sans-serif; // 1\n -ms-text-size-adjust: 100%; // 2\n -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined for any HTML5 element in IE 8/9.\n// Correct `block` display not defined for `details` or `summary` in IE 10/11\n// and Firefox.\n// Correct `block` display not defined for `main` in IE 11.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block; // 1\n vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9/10.\n// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n background-color: transparent;\n}\n\n//\n// Improve readability of focused elements when they are also in an\n// active/hover state.\n//\n\na:active,\na:hover {\n outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n//\n\nabbr[title] {\n border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n//\n\nb,\nstrong {\n font-weight: bold;\n}\n\n//\n// Address styling not present in Safari and Chrome.\n//\n\ndfn {\n font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari, and Chrome.\n//\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n background: #ff0;\n color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsup {\n top: -0.5em;\n}\n\nsub {\n bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9/10.\n//\n\nimg {\n border: 0;\n}\n\n//\n// Correct overflow not hidden in IE 9/10/11.\n//\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari.\n//\n\nfigure {\n margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n box-sizing: content-box;\n height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n// Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit; // 1\n font: inherit; // 2\n margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10/11.\n//\n\nbutton {\n overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n// and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n// `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button; // 2\n cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box; // 1\n padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n//\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n box-sizing: content-box; //2\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9/10/11.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n border: 0; // 1\n padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9/10/11.\n//\n\ntextarea {\n overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\n\ntd,\nth {\n padding: 0;\n}\n","/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n// ==========================================================================\n// Print styles.\n// Inlined to avoid the additional HTTP request: h5bp.com/r\n// ==========================================================================\n\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important; // Black prints faster: h5bp.com/s\n box-shadow: none !important;\n text-shadow: none !important;\n }\n\n a,\n a:visited {\n text-decoration: underline;\n }\n\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n\n // Don't show links that are fragment identifiers,\n // or use the `javascript:` pseudo protocol\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n\n thead {\n display: table-header-group; // h5bp.com/t\n }\n\n tr,\n img {\n page-break-inside: avoid;\n }\n\n img {\n max-width: 100% !important;\n }\n\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n\n h2,\n h3 {\n page-break-after: avoid;\n }\n\n // Bootstrap specific changes start\n\n // Bootstrap components\n .navbar {\n display: none;\n }\n .btn,\n .dropup > .btn {\n > .caret {\n border-top-color: #000 !important;\n }\n }\n .label {\n border: 1px solid #000;\n }\n\n .table {\n border-collapse: collapse !important;\n\n td,\n th {\n background-color: #fff !important;\n }\n }\n .table-bordered {\n th,\n td {\n border: 1px solid #ddd !important;\n }\n }\n\n // Bootstrap specific changes end\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// Star \n\n// Import the fonts\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('@{icon-font-path}@{icon-font-name}.eot');\n src: url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype'),\n url('@{icon-font-path}@{icon-font-name}.woff2') format('woff2'),\n url('@{icon-font-path}@{icon-font-name}.woff') format('woff'),\n url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype'),\n url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg');\n}\n\n// Catchall baseclass\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk { &:before { content: \"\\2a\"; } }\n.glyphicon-plus { &:before { content: \"\\2b\"; } }\n.glyphicon-euro,\n.glyphicon-eur { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil { &:before { content: \"\\270f\"; } }\n.glyphicon-glass { &:before { content: \"\\e001\"; } }\n.glyphicon-music { &:before { content: \"\\e002\"; } }\n.glyphicon-search { &:before { content: \"\\e003\"; } }\n.glyphicon-heart { &:before { content: \"\\e005\"; } }\n.glyphicon-star { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty { &:before { content: \"\\e007\"; } }\n.glyphicon-user { &:before { content: \"\\e008\"; } }\n.glyphicon-film { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large { &:before { content: \"\\e010\"; } }\n.glyphicon-th { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list { &:before { content: \"\\e012\"; } }\n.glyphicon-ok { &:before { content: \"\\e013\"; } }\n.glyphicon-remove { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out { &:before { content: \"\\e016\"; } }\n.glyphicon-off { &:before { content: \"\\e017\"; } }\n.glyphicon-signal { &:before { content: \"\\e018\"; } }\n.glyphicon-cog { &:before { content: \"\\e019\"; } }\n.glyphicon-trash { &:before { content: \"\\e020\"; } }\n.glyphicon-home { &:before { content: \"\\e021\"; } }\n.glyphicon-file { &:before { content: \"\\e022\"; } }\n.glyphicon-time { &:before { content: \"\\e023\"; } }\n.glyphicon-road { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt { &:before { content: \"\\e025\"; } }\n.glyphicon-download { &:before { content: \"\\e026\"; } }\n.glyphicon-upload { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt { &:before { content: \"\\e032\"; } }\n.glyphicon-lock { &:before { content: \"\\e033\"; } }\n.glyphicon-flag { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode { &:before { content: \"\\e040\"; } }\n.glyphicon-tag { &:before { content: \"\\e041\"; } }\n.glyphicon-tags { &:before { content: \"\\e042\"; } }\n.glyphicon-book { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark { &:before { content: \"\\e044\"; } }\n.glyphicon-print { &:before { content: \"\\e045\"; } }\n.glyphicon-camera { &:before { content: \"\\e046\"; } }\n.glyphicon-font { &:before { content: \"\\e047\"; } }\n.glyphicon-bold { &:before { content: \"\\e048\"; } }\n.glyphicon-italic { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify { &:before { content: \"\\e055\"; } }\n.glyphicon-list { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video { &:before { content: \"\\e059\"; } }\n.glyphicon-picture { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust { &:before { content: \"\\e063\"; } }\n.glyphicon-tint { &:before { content: \"\\e064\"; } }\n.glyphicon-edit { &:before { content: \"\\e065\"; } }\n.glyphicon-share { &:before { content: \"\\e066\"; } }\n.glyphicon-check { &:before { content: \"\\e067\"; } }\n.glyphicon-move { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward { &:before { content: \"\\e070\"; } }\n.glyphicon-backward { &:before { content: \"\\e071\"; } }\n.glyphicon-play { &:before { content: \"\\e072\"; } }\n.glyphicon-pause { &:before { content: \"\\e073\"; } }\n.glyphicon-stop { &:before { content: \"\\e074\"; } }\n.glyphicon-forward { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward { &:before { content: \"\\e077\"; } }\n.glyphicon-eject { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign { &:before { content: \"\\e101\"; } }\n.glyphicon-gift { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf { &:before { content: \"\\e103\"; } }\n.glyphicon-fire { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign { &:before { content: \"\\e107\"; } }\n.glyphicon-plane { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar { &:before { content: \"\\e109\"; } }\n.glyphicon-random { &:before { content: \"\\e110\"; } }\n.glyphicon-comment { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn { &:before { content: \"\\e122\"; } }\n.glyphicon-bell { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down { &:before { content: \"\\e134\"; } }\n.glyphicon-globe { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks { &:before { content: \"\\e137\"; } }\n.glyphicon-filter { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty { &:before { content: \"\\e143\"; } }\n.glyphicon-link { &:before { content: \"\\e144\"; } }\n.glyphicon-phone { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin { &:before { content: \"\\e146\"; } }\n.glyphicon-usd { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp { &:before { content: \"\\e149\"; } }\n.glyphicon-sort { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked { &:before { content: \"\\e157\"; } }\n.glyphicon-expand { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in { &:before { content: \"\\e161\"; } }\n.glyphicon-flash { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window { &:before { content: \"\\e164\"; } }\n.glyphicon-record { &:before { content: \"\\e165\"; } }\n.glyphicon-save { &:before { content: \"\\e166\"; } }\n.glyphicon-open { &:before { content: \"\\e167\"; } }\n.glyphicon-saved { &:before { content: \"\\e168\"; } }\n.glyphicon-import { &:before { content: \"\\e169\"; } }\n.glyphicon-export { &:before { content: \"\\e170\"; } }\n.glyphicon-send { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery { &:before { content: \"\\e179\"; } }\n.glyphicon-header { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt { &:before { content: \"\\e183\"; } }\n.glyphicon-tower { &:before { content: \"\\e184\"; } }\n.glyphicon-stats { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1 { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1 { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1 { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous { &:before { content: \"\\e200\"; } }\n.glyphicon-cd { &:before { content: \"\\e201\"; } }\n.glyphicon-save-file { &:before { content: \"\\e202\"; } }\n.glyphicon-open-file { &:before { content: \"\\e203\"; } }\n.glyphicon-level-up { &:before { content: \"\\e204\"; } }\n.glyphicon-copy { &:before { content: \"\\e205\"; } }\n.glyphicon-paste { &:before { content: \"\\e206\"; } }\n// The following 2 Glyphicons are omitted for the time being because\n// they currently use Unicode codepoints that are outside the\n// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle\n// non-BMP codepoints in CSS string escapes, and thus can't display these two icons.\n// Notably, the bug affects some older versions of the Android Browser.\n// More info: https://github.com/twbs/bootstrap/issues/10106\n// .glyphicon-door { &:before { content: \"\\1f6aa\"; } }\n// .glyphicon-key { &:before { content: \"\\1f511\"; } }\n.glyphicon-alert { &:before { content: \"\\e209\"; } }\n.glyphicon-equalizer { &:before { content: \"\\e210\"; } }\n.glyphicon-king { &:before { content: \"\\e211\"; } }\n.glyphicon-queen { &:before { content: \"\\e212\"; } }\n.glyphicon-pawn { &:before { content: \"\\e213\"; } }\n.glyphicon-bishop { &:before { content: \"\\e214\"; } }\n.glyphicon-knight { &:before { content: \"\\e215\"; } }\n.glyphicon-baby-formula { &:before { content: \"\\e216\"; } }\n.glyphicon-tent { &:before { content: \"\\26fa\"; } }\n.glyphicon-blackboard { &:before { content: \"\\e218\"; } }\n.glyphicon-bed { &:before { content: \"\\e219\"; } }\n.glyphicon-apple { &:before { content: \"\\f8ff\"; } }\n.glyphicon-erase { &:before { content: \"\\e221\"; } }\n.glyphicon-hourglass { &:before { content: \"\\231b\"; } }\n.glyphicon-lamp { &:before { content: \"\\e223\"; } }\n.glyphicon-duplicate { &:before { content: \"\\e224\"; } }\n.glyphicon-piggy-bank { &:before { content: \"\\e225\"; } }\n.glyphicon-scissors { &:before { content: \"\\e226\"; } }\n.glyphicon-bitcoin { &:before { content: \"\\e227\"; } }\n.glyphicon-btc { &:before { content: \"\\e227\"; } }\n.glyphicon-xbt { &:before { content: \"\\e227\"; } }\n.glyphicon-yen { &:before { content: \"\\00a5\"; } }\n.glyphicon-jpy { &:before { content: \"\\00a5\"; } }\n.glyphicon-ruble { &:before { content: \"\\20bd\"; } }\n.glyphicon-rub { &:before { content: \"\\20bd\"; } }\n.glyphicon-scale { &:before { content: \"\\e230\"; } }\n.glyphicon-ice-lolly { &:before { content: \"\\e231\"; } }\n.glyphicon-ice-lolly-tasted { &:before { content: \"\\e232\"; } }\n.glyphicon-education { &:before { content: \"\\e233\"; } }\n.glyphicon-option-horizontal { &:before { content: \"\\e234\"; } }\n.glyphicon-option-vertical { &:before { content: \"\\e235\"; } }\n.glyphicon-menu-hamburger { &:before { content: \"\\e236\"; } }\n.glyphicon-modal-window { &:before { content: \"\\e237\"; } }\n.glyphicon-oil { &:before { content: \"\\e238\"; } }\n.glyphicon-grain { &:before { content: \"\\e239\"; } }\n.glyphicon-sunglasses { &:before { content: \"\\e240\"; } }\n.glyphicon-text-size { &:before { content: \"\\e241\"; } }\n.glyphicon-text-color { &:before { content: \"\\e242\"; } }\n.glyphicon-text-background { &:before { content: \"\\e243\"; } }\n.glyphicon-object-align-top { &:before { content: \"\\e244\"; } }\n.glyphicon-object-align-bottom { &:before { content: \"\\e245\"; } }\n.glyphicon-object-align-horizontal{ &:before { content: \"\\e246\"; } }\n.glyphicon-object-align-left { &:before { content: \"\\e247\"; } }\n.glyphicon-object-align-vertical { &:before { content: \"\\e248\"; } }\n.glyphicon-object-align-right { &:before { content: \"\\e249\"; } }\n.glyphicon-triangle-right { &:before { content: \"\\e250\"; } }\n.glyphicon-triangle-left { &:before { content: \"\\e251\"; } }\n.glyphicon-triangle-bottom { &:before { content: \"\\e252\"; } }\n.glyphicon-triangle-top { &:before { content: \"\\e253\"; } }\n.glyphicon-console { &:before { content: \"\\e254\"; } }\n.glyphicon-superscript { &:before { content: \"\\e255\"; } }\n.glyphicon-subscript { &:before { content: \"\\e256\"; } }\n.glyphicon-menu-left { &:before { content: \"\\e257\"; } }\n.glyphicon-menu-right { &:before { content: \"\\e258\"; } }\n.glyphicon-menu-down { &:before { content: \"\\e259\"; } }\n.glyphicon-menu-up { &:before { content: \"\\e260\"; } }\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n .box-sizing(border-box);\n}\n*:before,\n*:after {\n .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n font-family: @font-family-base;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @text-color;\n background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\n\n// Links\n\na {\n color: @link-color;\n text-decoration: none;\n\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n }\n\n &:focus {\n .tab-focus();\n }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n margin: 0;\n}\n\n\n// Images\n\nimg {\n vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n padding: @thumbnail-padding;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n // Keep them at most 100% wide\n .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n margin-top: @line-height-computed;\n margin-bottom: @line-height-computed;\n border: 0;\n border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content/\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0,0,0,0);\n border: 0;\n}\n\n// Use in conjunction with .sr-only to only display content when it's focused.\n// Useful for \"Skip to main content\" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n// Credit: HTML5 Boilerplate\n\n.sr-only-focusable {\n &:active,\n &:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n }\n}\n\n\n// iOS \"clickable elements\" fix for role=\"button\"\n//\n// Fixes \"clickability\" issue (and more generally, the firing of events such as focus as well)\n// for traditionally non-focusable elements with role=\"button\"\n// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n\n[role=\"button\"] {\n cursor: pointer;\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// WebKit-style focus\n\n.tab-focus() {\n // Default\n outline: thin dotted;\n // WebKit\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n","// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size. Note that the\n// spelling of `min--moz-device-pixel-ratio` is intentional.\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n font-family: @headings-font-family;\n font-weight: @headings-font-weight;\n line-height: @headings-line-height;\n color: @headings-color;\n\n small,\n .small {\n font-weight: normal;\n line-height: 1;\n color: @headings-small-color;\n }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n margin-top: @line-height-computed;\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 65%;\n }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n margin-top: (@line-height-computed / 2);\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 75%;\n }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n margin-bottom: @line-height-computed;\n font-size: floor((@font-size-base * 1.15));\n font-weight: 300;\n line-height: 1.4;\n\n @media (min-width: @screen-sm-min) {\n font-size: (@font-size-base * 1.5);\n }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: (12px small font / 14px base font) * 100% = about 85%\nsmall,\n.small {\n font-size: floor((100% * @font-size-small / @font-size-base));\n}\n\nmark,\n.mark {\n background-color: @state-warning-bg;\n padding: .2em;\n}\n\n// Alignment\n.text-left { text-align: left; }\n.text-right { text-align: right; }\n.text-center { text-align: center; }\n.text-justify { text-align: justify; }\n.text-nowrap { white-space: nowrap; }\n\n// Transformation\n.text-lowercase { text-transform: lowercase; }\n.text-uppercase { text-transform: uppercase; }\n.text-capitalize { text-transform: capitalize; }\n\n// Contextual colors\n.text-muted {\n color: @text-muted;\n}\n.text-primary {\n .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n // Given the contrast here, this is the only class to have its color inverted\n // automatically.\n color: #fff;\n .bg-variant(@brand-primary);\n}\n.bg-success {\n .bg-variant(@state-success-bg);\n}\n.bg-info {\n .bg-variant(@state-info-bg);\n}\n.bg-warning {\n .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n padding-bottom: ((@line-height-computed / 2) - 1);\n margin: (@line-height-computed * 2) 0 @line-height-computed;\n border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// -------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n margin-top: 0;\n margin-bottom: (@line-height-computed / 2);\n ul,\n ol {\n margin-bottom: 0;\n }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n .list-unstyled();\n margin-left: -5px;\n\n > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n }\n}\n\n// Description Lists\ndl {\n margin-top: 0; // Remove browser default\n margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n line-height: @line-height-base;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n.dl-horizontal {\n dd {\n &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n }\n\n @media (min-width: @grid-float-breakpoint) {\n dt {\n float: left;\n width: (@dl-horizontal-offset - 20);\n clear: left;\n text-align: right;\n .text-overflow();\n }\n dd {\n margin-left: @dl-horizontal-offset;\n }\n }\n}\n\n\n// Misc\n// -------------------------\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n font-size: 90%;\n .text-uppercase();\n}\n\n// Blockquotes\nblockquote {\n padding: (@line-height-computed / 2) @line-height-computed;\n margin: 0 0 @line-height-computed;\n font-size: @blockquote-font-size;\n border-left: 5px solid @blockquote-border-color;\n\n p,\n ul,\n ol {\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Note: Deprecated small and .small as of v3.1.0\n // Context: https://github.com/twbs/bootstrap/issues/11660\n footer,\n small,\n .small {\n display: block;\n font-size: 80%; // back to default font-size\n line-height: @line-height-base;\n color: @blockquote-small-color;\n\n &:before {\n content: '\\2014 \\00A0'; // em dash, nbsp\n }\n }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid @blockquote-border-color;\n border-left: 0;\n text-align: right;\n\n // Account for citation\n footer,\n small,\n .small {\n &:before { content: ''; }\n &:after {\n content: '\\00A0 \\2014'; // nbsp, em dash\n }\n }\n}\n\n// Addresses\naddress {\n margin-bottom: @line-height-computed;\n font-style: normal;\n line-height: @line-height-base;\n}\n","// Typography\n\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover,\n a&:focus {\n color: darken(@color, 10%);\n }\n}\n","// Contextual backgrounds\n\n.bg-variant(@color) {\n background-color: @color;\n a&:hover,\n a&:focus {\n background-color: darken(@color, 10%);\n }\n}\n","// Text overflow\n// Requires inline-block or block for proper styling\n\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: @code-color;\n background-color: @code-bg;\n border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: @kbd-color;\n background-color: @kbd-bg;\n border-radius: @border-radius-small;\n box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n\n kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n }\n}\n\n// Blocks of code\npre {\n display: block;\n padding: ((@line-height-computed - 1) / 2);\n margin: 0 0 (@line-height-computed / 2);\n font-size: (@font-size-base - 1); // 14px to 13px\n line-height: @line-height-base;\n word-break: break-all;\n word-wrap: break-word;\n color: @pre-color;\n background-color: @pre-bg;\n border: 1px solid @pre-border-color;\n border-radius: @border-radius-base;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n max-height: @pre-scrollable-max-height;\n overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n .container-fixed();\n\n @media (min-width: @screen-sm-min) {\n width: @container-sm;\n }\n @media (min-width: @screen-md-min) {\n width: @container-md;\n }\n @media (min-width: @screen-lg-min) {\n width: @container-lg;\n }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n .make-grid(lg);\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n// Centered container element\n.container-fixed(@gutter: @grid-gutter-width) {\n margin-right: auto;\n margin-left: auto;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: ceil((@gutter / -2));\n margin-right: floor((@gutter / -2));\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n margin-left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-push(@columns) {\n left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-pull(@columns) {\n right: percentage((@columns / @grid-columns));\n}\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n","// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: ceil((@grid-gutter-width / 2));\n padding-right: floor((@grid-gutter-width / 2));\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {\n .col-@{class}-push-0 {\n left: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {\n .col-@{class}-pull-0 {\n right: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n background-color: @table-bg;\n}\ncaption {\n padding-top: @table-cell-padding;\n padding-bottom: @table-cell-padding;\n color: @text-muted;\n text-align: left;\n}\nth {\n text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: @line-height-computed;\n // Cells\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-cell-padding;\n line-height: @line-height-base;\n vertical-align: top;\n border-top: 1px solid @table-border-color;\n }\n }\n }\n // Bottom align for column headings\n > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid @table-border-color;\n }\n // Remove top border from thead by default\n > caption + thead,\n > colgroup + thead,\n > thead:first-child {\n > tr:first-child {\n > th,\n > td {\n border-top: 0;\n }\n }\n }\n // Account for multiple tbody instances\n > tbody + tbody {\n border-top: 2px solid @table-border-color;\n }\n\n // Nesting\n .table {\n background-color: @body-bg;\n }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-condensed-cell-padding;\n }\n }\n }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n border: 1px solid @table-border-color;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n border: 1px solid @table-border-color;\n }\n }\n }\n > thead > tr {\n > th,\n > td {\n border-bottom-width: 2px;\n }\n }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n > tbody > tr:nth-of-type(odd) {\n background-color: @table-bg-accent;\n }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n > tbody > tr:hover {\n background-color: @table-bg-hover;\n }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-column;\n}\ntable {\n td,\n th {\n &[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-cell;\n }\n }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)\n\n @media screen and (max-width: @screen-xs-max) {\n width: 100%;\n margin-bottom: (@line-height-computed * 0.75);\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid @table-border-color;\n\n // Tighten up spacing\n > .table {\n margin-bottom: 0;\n\n // Ensure the content doesn't wrap\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n white-space: nowrap;\n }\n }\n }\n }\n\n // Special overrides for the bordered tables\n > .table-bordered {\n border: 0;\n\n // Nuke the appropriate borders so that the parent can handle them\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n\n // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n // chances are there will be only one `tr` in a `thead` and that would\n // remove the border altogether.\n > tbody,\n > tfoot {\n > tr:last-child {\n > th,\n > td {\n border-bottom: 0;\n }\n }\n }\n\n }\n }\n}\n","// Tables\n\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &:hover > .@{state},\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n // so we reset that to ensure it behaves more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359.\n min-width: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: @line-height-computed;\n font-size: (@font-size-base * 1.5);\n line-height: inherit;\n color: @legend-color;\n border: 0;\n border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n display: inline-block;\n max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)\n margin-bottom: 5px;\n font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9; // IE8-9\n line-height: normal;\n}\n\ninput[type=\"file\"] {\n display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n .tab-focus();\n}\n\n// Adjust output element\noutput {\n display: block;\n padding-top: (@padding-base-vertical + 1);\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n display: block;\n width: 100%;\n height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n background-color: @input-bg;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid @input-border;\n border-radius: @input-border-radius; // Note: This has no effect on s in some browsers, due to the limited stylability of s in CSS.\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n // Customize the `:focus` state to imitate native WebKit styles.\n .form-control-focus();\n\n // Placeholder\n .placeholder();\n\n // Disabled and read-only inputs\n //\n // HTML5 says that controls under a fieldset > legend:first-child won't be\n // disabled if the fieldset is disabled. Due to implementation difficulty, we\n // don't honor that edge case; we style them as disabled anyway.\n &[disabled],\n &[readonly],\n fieldset[disabled] & {\n background-color: @input-bg-disabled;\n opacity: 1; // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655\n }\n\n &[disabled],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n\n // Reset height for `textarea`s\n textarea& {\n height: auto;\n }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n\n\n// Special styles for iOS temporal inputs\n//\n// In Mobile Safari, setting `display: block` on temporal inputs causes the\n// text within the input to become vertically misaligned. As a workaround, we\n// set a pixel line-height that matches the given height of the input, but only\n// for Safari. See https://bugs.webkit.org/show_bug.cgi?id=139848\n//\n// Note that as of 8.3, iOS doesn't support `datetime` or `week`.\n\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"],\n input[type=\"time\"],\n input[type=\"datetime-local\"],\n input[type=\"month\"] {\n &.form-control {\n line-height: @input-height-base;\n }\n\n &.input-sm,\n .input-group-sm & {\n line-height: @input-height-small;\n }\n\n &.input-lg,\n .input-group-lg & {\n line-height: @input-height-large;\n }\n }\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n margin-bottom: @form-group-margin-bottom;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n\n label {\n min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-left: -20px;\n margin-top: 4px \\9;\n}\n\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n// Some special care is needed because s don't inherit their parent's `cursor`.\n//\n// Note: Neither radios nor checkboxes can be readonly.\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n &[disabled],\n &.disabled,\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n}\n// These classes are used directly on s\n.radio-inline,\n.checkbox-inline {\n &.disabled,\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n}\n// These classes are used on elements with descendants\n.radio,\n.checkbox {\n &.disabled,\n fieldset[disabled] & {\n label {\n cursor: @cursor-disabled;\n }\n }\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n // Size it appropriately next to real form controls\n padding-top: (@padding-base-vertical + 1);\n padding-bottom: (@padding-base-vertical + 1);\n // Remove default margin from `p`\n margin-bottom: 0;\n min-height: (@line-height-computed + @font-size-base);\n\n &.input-lg,\n &.input-sm {\n padding-left: 0;\n padding-right: 0;\n }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n//\n// The `.form-group-* form-control` variations are sadly duplicated to avoid the\n// issue documented in https://github.com/twbs/bootstrap/issues/15074.\n\n.input-sm {\n .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @input-border-radius-small);\n}\n.form-group-sm {\n .form-control {\n height: @input-height-small;\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n line-height: @line-height-small;\n border-radius: @input-border-radius-small;\n }\n select.form-control {\n height: @input-height-small;\n line-height: @input-height-small;\n }\n textarea.form-control,\n select[multiple].form-control {\n height: auto;\n }\n .form-control-static {\n height: @input-height-small;\n min-height: (@line-height-computed + @font-size-small);\n padding: (@padding-small-vertical + 1) @padding-small-horizontal;\n font-size: @font-size-small;\n line-height: @line-height-small;\n }\n}\n\n.input-lg {\n .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @input-border-radius-large);\n}\n.form-group-lg {\n .form-control {\n height: @input-height-large;\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-large;\n border-radius: @input-border-radius-large;\n }\n select.form-control {\n height: @input-height-large;\n line-height: @input-height-large;\n }\n textarea.form-control,\n select[multiple].form-control {\n height: auto;\n }\n .form-control-static {\n height: @input-height-large;\n min-height: (@line-height-computed + @font-size-large);\n padding: (@padding-large-vertical + 1) @padding-large-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-large;\n }\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n // Enable absolute positioning\n position: relative;\n\n // Ensure icons don't overlap text\n .form-control {\n padding-right: (@input-height-base * 1.25);\n }\n}\n// Feedback icon (requires .glyphicon classes)\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2; // Ensure icon is above input groups\n display: block;\n width: @input-height-base;\n height: @input-height-base;\n line-height: @input-height-base;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: @input-height-large;\n height: @input-height-large;\n line-height: @input-height-large;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: @input-height-small;\n height: @input-height-small;\n line-height: @input-height-small;\n}\n\n// Feedback states\n.has-success {\n .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n// Reposition feedback icon if input has visible label above\n.has-feedback label {\n\n & ~ .form-control-feedback {\n top: (@line-height-computed + 5); // Height of the `label` and its margin\n }\n &.sr-only ~ .form-control-feedback {\n top: 0;\n }\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n display: block; // account for any element using help-block\n margin-top: 5px;\n margin-bottom: 10px;\n color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n // Kick in the inline\n @media (min-width: @screen-sm-min) {\n // Inline-block all the things for \"inline\"\n .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // In navbar-form, allow folks to *not* use `.form-group`\n .form-control {\n display: inline-block;\n width: auto; // Prevent labels from stacking above inputs in `.form-group`\n vertical-align: middle;\n }\n\n // Make static controls behave like regular ones\n .form-control-static {\n display: inline-block;\n }\n\n .input-group {\n display: inline-table;\n vertical-align: middle;\n\n .input-group-addon,\n .input-group-btn,\n .form-control {\n width: auto;\n }\n }\n\n // Input groups need that 100% width though\n .input-group > .form-control {\n width: 100%;\n }\n\n .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // Remove default margin on radios/checkboxes that were used for stacking, and\n // then undo the floating of radios and checkboxes to match.\n .radio,\n .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n\n label {\n padding-left: 0;\n }\n }\n .radio input[type=\"radio\"],\n .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n\n // Re-override the feedback icon.\n .has-feedback .form-control-feedback {\n top: 0;\n }\n }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n // Consistent vertical alignment of radios and checkboxes\n //\n // Labels also get some reset styles, but that is scoped to a media query below.\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n }\n // Account for padding we're adding to ensure the alignment and of help text\n // and other content below items\n .radio,\n .checkbox {\n min-height: (@line-height-computed + (@padding-base-vertical + 1));\n }\n\n // Make form groups behave like rows\n .form-group {\n .make-row();\n }\n\n // Reset spacing and right align labels, but scope to media queries so that\n // labels on narrow viewports stack the same as a default form example.\n @media (min-width: @screen-sm-min) {\n .control-label {\n text-align: right;\n margin-bottom: 0;\n padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n }\n }\n\n // Validation states\n //\n // Reposition the icon because it's now within a grid column and columns have\n // `position: relative;` on them. Also accounts for the grid gutter padding.\n .has-feedback .form-control-feedback {\n right: floor((@grid-gutter-width / 2));\n }\n\n // Form group sizes\n //\n // Quick utility class for applying `.input-lg` and `.input-sm` styles to the\n // inputs and labels within a `.form-group`.\n .form-group-lg {\n @media (min-width: @screen-sm-min) {\n .control-label {\n padding-top: ((@padding-large-vertical * @line-height-large) + 1);\n font-size: @font-size-large;\n }\n }\n }\n .form-group-sm {\n @media (min-width: @screen-sm-min) {\n .control-label {\n padding-top: (@padding-small-vertical + 1);\n font-size: @font-size-small;\n }\n }\n }\n}\n","// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n // Color the label and help text\n .help-block,\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline,\n &.radio label,\n &.checkbox label,\n &.radio-inline label,\n &.checkbox-inline label {\n color: @text-color;\n }\n // Set the border and box shadow on specific inputs to match\n .form-control {\n border-color: @border-color;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n &:focus {\n border-color: darken(@border-color, 10%);\n @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n .box-shadow(@shadow);\n }\n }\n // Set validation states also for addons\n .input-group-addon {\n color: @text-color;\n border-color: @border-color;\n background-color: @background-color;\n }\n // Optional feedback icon\n .form-control-feedback {\n color: @text-color;\n }\n}\n\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-border-focus` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n.form-control-focus(@color: @input-border-focus) {\n @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n &:focus {\n border-color: @color;\n outline: 0;\n .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. ``\n// element gets special love because it's special, and that's a fact!\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n height: @input-height;\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n\n select& {\n height: @input-height;\n line-height: @input-height;\n }\n\n textarea&,\n select[multiple]& {\n height: auto;\n }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n display: inline-block;\n margin-bottom: 0; // For input.btn\n font-weight: @btn-font-weight;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n white-space: nowrap;\n .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @btn-border-radius-base);\n .user-select(none);\n\n &,\n &:active,\n &.active {\n &:focus,\n &.focus {\n .tab-focus();\n }\n }\n\n &:hover,\n &:focus,\n &.focus {\n color: @btn-default-color;\n text-decoration: none;\n }\n\n &:active,\n &.active {\n outline: 0;\n background-image: none;\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n .opacity(.65);\n .box-shadow(none);\n }\n\n a& {\n &.disabled,\n fieldset[disabled] & {\n pointer-events: none; // Future-proof disabling of clicks on `` elements\n }\n }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n color: @link-color;\n font-weight: normal;\n border-radius: 0;\n\n &,\n &:active,\n &.active,\n &[disabled],\n fieldset[disabled] & {\n background-color: transparent;\n .box-shadow(none);\n }\n &,\n &:hover,\n &:focus,\n &:active {\n border-color: transparent;\n }\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n background-color: transparent;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @btn-link-disabled-color;\n text-decoration: none;\n }\n }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n // line-height: ensure even-numbered height of button next to large input\n .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @btn-border-radius-large);\n}\n.btn-sm {\n // line-height: ensure proper height of button next to small input\n .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);\n}\n.btn-xs {\n .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n display: block;\n width: 100%;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n &.btn-block {\n width: 100%;\n }\n}\n","// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:focus,\n &.focus {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 25%);\n }\n &:hover {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 12%);\n\n &:hover,\n &:focus,\n &.focus {\n color: @color;\n background-color: darken(@background, 17%);\n border-color: darken(@border, 25%);\n }\n }\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n background-image: none;\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n","// Opacity\n\n.opacity(@opacity) {\n opacity: @opacity;\n // IE8 filter\n @opacity-ie: (@opacity * 100);\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.\n\n.fade {\n opacity: 0;\n .transition(opacity .15s linear);\n &.in {\n opacity: 1;\n }\n}\n\n.collapse {\n display: none;\n\n &.in { display: block; }\n tr&.in { display: table-row; }\n tbody&.in { display: table-row-group; }\n}\n\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n .transition-property(~\"height, visibility\");\n .transition-duration(.35s);\n .transition-timing-function(ease);\n}\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: @caret-width-base dashed;\n border-top: @caret-width-base solid ~\"\\9\"; // IE8\n border-right: @caret-width-base solid transparent;\n border-left: @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropup,\n.dropdown {\n position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: @zindex-dropdown;\n display: none; // none by default, but block on \"open\" of the menu\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0; // override default ul\n list-style: none;\n font-size: @font-size-base;\n text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\n background-color: @dropdown-bg;\n border: 1px solid @dropdown-fallback-border; // IE8 fallback\n border: 1px solid @dropdown-border;\n border-radius: @border-radius-base;\n .box-shadow(0 6px 12px rgba(0,0,0,.175));\n background-clip: padding-box;\n\n // Aligns the dropdown menu to right\n //\n // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n &.pull-right {\n right: 0;\n left: auto;\n }\n\n // Dividers (basically an hr) within the dropdown\n .divider {\n .nav-divider(@dropdown-divider-bg);\n }\n\n // Links within the dropdown menu\n > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: @line-height-base;\n color: @dropdown-link-color;\n white-space: nowrap; // prevent links from randomly breaking onto new lines\n }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n &:hover,\n &:focus {\n text-decoration: none;\n color: @dropdown-link-hover-color;\n background-color: @dropdown-link-hover-bg;\n }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-active-color;\n text-decoration: none;\n outline: 0;\n background-color: @dropdown-link-active-bg;\n }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-disabled-color;\n }\n\n // Nuke hover/focus effects\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none; // Remove CSS gradient\n .reset-filter();\n cursor: @cursor-disabled;\n }\n}\n\n// Open state for the dropdown\n.open {\n // Show the menu\n > .dropdown-menu {\n display: block;\n }\n\n // Remove the outline when :focus is triggered\n > a {\n outline: 0;\n }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n left: auto; // Reset the default from `.dropdown-menu`\n right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: @font-size-small;\n line-height: @line-height-base;\n color: @dropdown-header-color;\n white-space: nowrap; // as with > li > a\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n // Reverse the caret\n .caret {\n border-top: 0;\n border-bottom: @caret-width-base dashed;\n border-bottom: @caret-width-base solid ~\"\\9\"; // IE8\n content: \"\";\n }\n // Different positioning for bottom up menu\n .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-right {\n .dropdown-menu {\n .dropdown-menu-right();\n }\n // Necessary for overrides of the default right aligned menu.\n // Will remove come v4 in all likelihood.\n .dropdown-menu-left {\n .dropdown-menu-left();\n }\n }\n}\n","// Horizontal dividers\n//\n// Dividers (basically an hr) within dropdowns and nav lists\n\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle; // match .btn alignment given font-size hack above\n > .btn {\n position: relative;\n float: left;\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active,\n &.active {\n z-index: 2;\n }\n }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n .btn + .btn,\n .btn + .btn-group,\n .btn-group + .btn,\n .btn-group + .btn-group {\n margin-left: -1px;\n }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n margin-left: -5px; // Offset the first child's margin\n &:extend(.clearfix all);\n\n .btn,\n .btn-group,\n .input-group {\n float: left;\n }\n > .btn,\n > .btn-group,\n > .input-group {\n margin-left: 5px;\n }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n margin-left: 0;\n &:not(:last-child):not(.dropdown-toggle) {\n .border-right-radius(0);\n }\n}\n// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-right-radius(0);\n }\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n // Show no shadow for `.btn-link` since it has no other button styles.\n &.btn-link {\n .box-shadow(none);\n }\n}\n\n\n// Reposition the caret\n.btn .caret {\n margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n border-width: @caret-width-large @caret-width-large 0;\n border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n > .btn,\n > .btn-group,\n > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n }\n\n // Clear floats so dropdown menus can be properly placed\n > .btn-group {\n &:extend(.clearfix all);\n > .btn {\n float: none;\n }\n }\n\n > .btn + .btn,\n > .btn + .btn-group,\n > .btn-group + .btn,\n > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n }\n}\n\n.btn-group-vertical > .btn {\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n &:first-child:not(:last-child) {\n border-top-right-radius: @btn-border-radius-base;\n .border-bottom-radius(0);\n }\n &:last-child:not(:first-child) {\n border-bottom-left-radius: @btn-border-radius-base;\n .border-top-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-bottom-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-top-radius(0);\n}\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n > .btn,\n > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n }\n > .btn-group .btn {\n width: 100%;\n }\n\n > .btn-group .dropdown-menu {\n left: auto;\n }\n}\n\n\n// Checkbox and radio options\n//\n// In order to support the browser's form validation feedback, powered by the\n// `required` attribute, we have to \"hide\" the inputs via `clip`. We cannot use\n// `display: none;` or `visibility: hidden;` as that also hides the popover.\n// Simply visually hiding the inputs via `opacity` would leave them clickable in\n// certain cases which is prevented by using `clip` and `pointer-events`.\n// This way, we ensure a DOM element is visible to position the popover from.\n//\n// See https://github.com/twbs/bootstrap/pull/12794 and\n// https://github.com/twbs/bootstrap/pull/14559 for more information.\n\n[data-toggle=\"buttons\"] {\n > .btn,\n > .btn-group > .btn {\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0,0,0,0);\n pointer-events: none;\n }\n }\n}\n","// Single side border-radius\n\n.border-top-radius(@radius) {\n border-top-right-radius: @radius;\n border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-bottom-left-radius: @radius;\n border-top-left-radius: @radius;\n}\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n position: relative; // For dropdowns\n display: table;\n border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n // Undo padding and float of grid classes\n &[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n }\n\n .form-control {\n // Ensure that the input is always above the *appended* addon button for\n // proper border colors.\n position: relative;\n z-index: 2;\n\n // IE9 fubars the placeholder attribute in text inputs and the arrows on\n // select elements in input groups. To fix it, we float the input. Details:\n // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n float: left;\n\n width: 100%;\n margin-bottom: 0;\n }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n .input-lg();\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n .input-sm();\n}\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n font-weight: normal;\n line-height: 1;\n color: @input-color;\n text-align: center;\n background-color: @input-group-addon-bg;\n border: 1px solid @input-group-addon-border-color;\n border-radius: @border-radius-base;\n\n // Sizing\n &.input-sm {\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n border-radius: @border-radius-small;\n }\n &.input-lg {\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n border-radius: @border-radius-large;\n }\n\n // Nuke default margins from checkboxes and radios to vertically center within.\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n margin-top: 0;\n }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n .border-right-radius(0);\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n .border-left-radius(0);\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n position: relative;\n // Jankily prevent input button groups from wrapping with `white-space` and\n // `font-size` in combination with `inline-block` on buttons.\n font-size: 0;\n white-space: nowrap;\n\n // Negative margin for spacing, position for bringing hovered/focused/actived\n // element above the siblings.\n > .btn {\n position: relative;\n + .btn {\n margin-left: -1px;\n }\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active {\n z-index: 2;\n }\n }\n\n // Negative margin to only have a 1px border between the two\n &:first-child {\n > .btn,\n > .btn-group {\n margin-right: -1px;\n }\n }\n &:last-child {\n > .btn,\n > .btn-group {\n z-index: 2;\n margin-left: -1px;\n }\n }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n margin-bottom: 0;\n padding-left: 0; // Override default ul/ol\n list-style: none;\n &:extend(.clearfix all);\n\n > li {\n position: relative;\n display: block;\n\n > a {\n position: relative;\n display: block;\n padding: @nav-link-padding;\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: @nav-link-hover-bg;\n }\n }\n\n // Disabled state sets text to gray and nukes hover/tab effects\n &.disabled > a {\n color: @nav-disabled-link-color;\n\n &:hover,\n &:focus {\n color: @nav-disabled-link-hover-color;\n text-decoration: none;\n background-color: transparent;\n cursor: @cursor-disabled;\n }\n }\n }\n\n // Open dropdowns\n .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @nav-link-hover-bg;\n border-color: @link-color;\n }\n }\n\n // Nav dividers (deprecated with v3.0.1)\n //\n // This should have been removed in v3 with the dropping of `.nav-list`, but\n // we missed it. We don't currently support this anywhere, but in the interest\n // of maintaining backward compatibility in case you use it, it's deprecated.\n .nav-divider {\n .nav-divider();\n }\n\n // Prevent IE8 from misplacing imgs\n //\n // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n > li > a > img {\n max-width: none;\n }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n border-bottom: 1px solid @nav-tabs-border-color;\n > li {\n float: left;\n // Make the list-items overlay the bottom border\n margin-bottom: -1px;\n\n // Actual tabs (as links)\n > a {\n margin-right: 2px;\n line-height: @line-height-base;\n border: 1px solid transparent;\n border-radius: @border-radius-base @border-radius-base 0 0;\n &:hover {\n border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n }\n }\n\n // Active state, and its :hover to override normal :hover\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-tabs-active-link-hover-color;\n background-color: @nav-tabs-active-link-hover-bg;\n border: 1px solid @nav-tabs-active-link-hover-border-color;\n border-bottom-color: transparent;\n cursor: default;\n }\n }\n }\n // pulling this in mainly for less shorthand\n &.nav-justified {\n .nav-justified();\n .nav-tabs-justified();\n }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n > li {\n float: left;\n\n // Links rendered as pills\n > a {\n border-radius: @nav-pills-border-radius;\n }\n + li {\n margin-left: 2px;\n }\n\n // Active state\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-pills-active-link-hover-color;\n background-color: @nav-pills-active-link-hover-bg;\n }\n }\n }\n}\n\n\n// Stacked pills\n.nav-stacked {\n > li {\n float: none;\n + li {\n margin-top: 2px;\n margin-left: 0; // no need for this gap between nav items\n }\n }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n width: 100%;\n\n > li {\n float: none;\n > a {\n text-align: center;\n margin-bottom: 5px;\n }\n }\n\n > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n }\n\n @media (min-width: @screen-sm-min) {\n > li {\n display: table-cell;\n width: 1%;\n > a {\n margin-bottom: 0;\n }\n }\n }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n border-bottom: 0;\n\n > li > a {\n // Override margin from .nav-tabs\n margin-right: 0;\n border-radius: @border-radius-base;\n }\n\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border: 1px solid @nav-tabs-justified-link-border-color;\n }\n\n @media (min-width: @screen-sm-min) {\n > li > a {\n border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n border-radius: @border-radius-base @border-radius-base 0 0;\n }\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border-bottom-color: @nav-tabs-justified-active-link-border-color;\n }\n }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n > .tab-pane {\n display: none;\n }\n > .active {\n display: block;\n }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n // make dropdown border overlap tab border\n margin-top: -1px;\n // Remove the top rounded corners here since there is a hard edge above the menu\n .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n position: relative;\n min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n margin-bottom: @navbar-margin-bottom;\n border: 1px solid transparent;\n\n // Prevent floats from breaking the navbar\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: @navbar-border-radius;\n }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n overflow-x: visible;\n padding-right: @navbar-padding-horizontal;\n padding-left: @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n &:extend(.clearfix all);\n -webkit-overflow-scrolling: touch;\n\n &.in {\n overflow-y: auto;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border-top: 0;\n box-shadow: none;\n\n &.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0; // Override default setting\n overflow: visible !important;\n }\n\n &.in {\n overflow-y: visible;\n }\n\n // Undo the collapse side padding for navbars with containers to ensure\n // alignment of right-aligned contents.\n .navbar-fixed-top &,\n .navbar-static-top &,\n .navbar-fixed-bottom & {\n padding-left: 0;\n padding-right: 0;\n }\n }\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n .navbar-collapse {\n max-height: @navbar-collapse-max-height;\n\n @media (max-device-width: @screen-xs-min) and (orientation: landscape) {\n max-height: 200px;\n }\n }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n > .navbar-header,\n > .navbar-collapse {\n margin-right: -@navbar-padding-horizontal;\n margin-left: -@navbar-padding-horizontal;\n\n @media (min-width: @grid-float-breakpoint) {\n margin-right: 0;\n margin-left: 0;\n }\n }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n z-index: @zindex-navbar;\n border-width: 0 0 1px;\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: @zindex-navbar-fixed;\n\n // Undo the rounded corners\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0; // override .navbar defaults\n border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n float: left;\n padding: @navbar-padding-vertical @navbar-padding-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-computed;\n height: @navbar-height;\n\n &:hover,\n &:focus {\n text-decoration: none;\n }\n\n > img {\n display: block;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n .navbar > .container &,\n .navbar > .container-fluid & {\n margin-left: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: @navbar-padding-horizontal;\n padding: 9px 10px;\n .navbar-vertical-align(34px);\n background-color: transparent;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n border-radius: @border-radius-base;\n\n // We remove the `outline` here, but later compensate by attaching `:hover`\n // styles to `:focus`.\n &:focus {\n outline: 0;\n }\n\n // Bars\n .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n }\n .icon-bar + .icon-bar {\n margin-top: 4px;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n display: none;\n }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: @line-height-computed;\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n > li > a,\n .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n > li > a {\n line-height: @line-height-computed;\n &:hover,\n &:focus {\n background-image: none;\n }\n }\n }\n }\n\n // Uncollapse the nav\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin: 0;\n\n > li {\n float: left;\n > a {\n padding-top: @navbar-padding-vertical;\n padding-bottom: @navbar-padding-vertical;\n }\n }\n }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n margin-left: -@navbar-padding-horizontal;\n margin-right: -@navbar-padding-horizontal;\n padding: 10px @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n\n // Mixin behavior for optimum display\n .form-inline();\n\n .form-group {\n @media (max-width: @grid-float-breakpoint-max) {\n margin-bottom: 5px;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n }\n\n // Vertically center in expanded, horizontal navbar\n .navbar-vertical-align(@input-height-base);\n\n // Undo 100% width for pull classes\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n .box-shadow(none);\n }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n .border-top-radius(@navbar-border-radius);\n .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n .navbar-vertical-align(@input-height-base);\n\n &.btn-sm {\n .navbar-vertical-align(@input-height-small);\n }\n &.btn-xs {\n .navbar-vertical-align(22);\n }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n .navbar-vertical-align(@line-height-computed);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin-left: @navbar-padding-horizontal;\n margin-right: @navbar-padding-horizontal;\n }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n//\n// Declared after the navbar components to ensure more specificity on the margins.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-left { .pull-left(); }\n .navbar-right {\n .pull-right();\n margin-right: -@navbar-padding-horizontal;\n\n ~ .navbar-right {\n margin-right: 0;\n }\n }\n}\n\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n background-color: @navbar-default-bg;\n border-color: @navbar-default-border;\n\n .navbar-brand {\n color: @navbar-default-brand-color;\n &:hover,\n &:focus {\n color: @navbar-default-brand-hover-color;\n background-color: @navbar-default-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-default-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-default-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n\n .navbar-toggle {\n border-color: @navbar-default-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-default-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-default-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: @navbar-default-border;\n }\n\n // Dropdown menu items\n .navbar-nav {\n // Remove background color from open dropdown\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-default-link-active-bg;\n color: @navbar-default-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n > li > a {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n }\n }\n\n\n // Links in navbars\n //\n // Add a class to ensure links outside the navbar nav are colored correctly.\n\n .navbar-link {\n color: @navbar-default-link-color;\n &:hover {\n color: @navbar-default-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n }\n }\n }\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n background-color: @navbar-inverse-bg;\n border-color: @navbar-inverse-border;\n\n .navbar-brand {\n color: @navbar-inverse-brand-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-brand-hover-color;\n background-color: @navbar-inverse-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-inverse-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-inverse-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n\n // Darken the responsive nav toggle\n .navbar-toggle {\n border-color: @navbar-inverse-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-inverse-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-inverse-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: darken(@navbar-inverse-bg, 7%);\n }\n\n // Dropdowns\n .navbar-nav {\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-inverse-link-active-bg;\n color: @navbar-inverse-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display\n .open .dropdown-menu {\n > .dropdown-header {\n border-color: @navbar-inverse-border;\n }\n .divider {\n background-color: @navbar-inverse-border;\n }\n > li > a {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n }\n }\n\n .navbar-link {\n color: @navbar-inverse-link-color;\n &:hover {\n color: @navbar-inverse-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n }\n }\n }\n}\n","// Navbar vertical align\n//\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n .clearfix();\n}\n.center-block {\n .center-block();\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n display: none !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n margin-bottom: @line-height-computed;\n list-style: none;\n background-color: @breadcrumb-bg;\n border-radius: @border-radius-base;\n\n > li {\n display: inline-block;\n\n + li:before {\n content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n padding: 0 5px;\n color: @breadcrumb-color;\n }\n }\n\n > .active {\n color: @breadcrumb-active-color;\n }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: @line-height-computed 0;\n border-radius: @border-radius-base;\n\n > li {\n display: inline; // Remove list-style and block-level defaults\n > a,\n > span {\n position: relative;\n float: left; // Collapse white-space\n padding: @padding-base-vertical @padding-base-horizontal;\n line-height: @line-height-base;\n text-decoration: none;\n color: @pagination-color;\n background-color: @pagination-bg;\n border: 1px solid @pagination-border;\n margin-left: -1px;\n }\n &:first-child {\n > a,\n > span {\n margin-left: 0;\n .border-left-radius(@border-radius-base);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius-base);\n }\n }\n }\n\n > li > a,\n > li > span {\n &:hover,\n &:focus {\n z-index: 3;\n color: @pagination-hover-color;\n background-color: @pagination-hover-bg;\n border-color: @pagination-hover-border;\n }\n }\n\n > .active > a,\n > .active > span {\n &,\n &:hover,\n &:focus {\n z-index: 2;\n color: @pagination-active-color;\n background-color: @pagination-active-bg;\n border-color: @pagination-active-border;\n cursor: default;\n }\n }\n\n > .disabled {\n > span,\n > span:hover,\n > span:focus,\n > a,\n > a:hover,\n > a:focus {\n color: @pagination-disabled-color;\n background-color: @pagination-disabled-bg;\n border-color: @pagination-disabled-border;\n cursor: @cursor-disabled;\n }\n }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n","// Pagination\n\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n padding-left: 0;\n margin: @line-height-computed 0;\n list-style: none;\n text-align: center;\n &:extend(.clearfix all);\n li {\n display: inline;\n > a,\n > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: @pager-bg;\n border: 1px solid @pager-border;\n border-radius: @pager-border-radius;\n }\n\n > a:hover,\n > a:focus {\n text-decoration: none;\n background-color: @pager-hover-bg;\n }\n }\n\n .next {\n > a,\n > span {\n float: right;\n }\n }\n\n .previous {\n > a,\n > span {\n float: left;\n }\n }\n\n .disabled {\n > a,\n > a:hover,\n > a:focus,\n > span {\n color: @pager-disabled-color;\n background-color: @pager-bg;\n cursor: @cursor-disabled;\n }\n }\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: @label-color;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n\n // Add hover effects, but only for links\n a& {\n &:hover,\n &:focus {\n color: @label-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Empty labels collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for labels in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n .label-variant(@label-default-bg);\n}\n\n.label-primary {\n .label-variant(@label-primary-bg);\n}\n\n.label-success {\n .label-variant(@label-success-bg);\n}\n\n.label-info {\n .label-variant(@label-info-bg);\n}\n\n.label-warning {\n .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n .label-variant(@label-danger-bg);\n}\n","// Labels\n\n.label-variant(@color) {\n background-color: @color;\n\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base class\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: @font-size-small;\n font-weight: @badge-font-weight;\n color: @badge-color;\n line-height: @badge-line-height;\n vertical-align: middle;\n white-space: nowrap;\n text-align: center;\n background-color: @badge-bg;\n border-radius: @badge-border-radius;\n\n // Empty badges collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for badges in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n\n .btn-xs &,\n .btn-group-xs > .btn & {\n top: 0;\n padding: 1px 5px;\n }\n\n // Hover state, but only for links\n a& {\n &:hover,\n &:focus {\n color: @badge-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Account for badges in navs\n .list-group-item.active > &,\n .nav-pills > .active > a > & {\n color: @badge-active-color;\n background-color: @badge-active-bg;\n }\n\n .list-group-item > & {\n float: right;\n }\n\n .list-group-item > & + & {\n margin-right: 5px;\n }\n\n .nav-pills > li > a > & {\n margin-left: 3px;\n }\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n padding-top: @jumbotron-padding;\n padding-bottom: @jumbotron-padding;\n margin-bottom: @jumbotron-padding;\n color: @jumbotron-color;\n background-color: @jumbotron-bg;\n\n h1,\n .h1 {\n color: @jumbotron-heading-color;\n }\n\n p {\n margin-bottom: (@jumbotron-padding / 2);\n font-size: @jumbotron-font-size;\n font-weight: 200;\n }\n\n > hr {\n border-top-color: darken(@jumbotron-bg, 10%);\n }\n\n .container &,\n .container-fluid & {\n border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n }\n\n .container {\n max-width: 100%;\n }\n\n @media screen and (min-width: @screen-sm-min) {\n padding-top: (@jumbotron-padding * 1.6);\n padding-bottom: (@jumbotron-padding * 1.6);\n\n .container &,\n .container-fluid & {\n padding-left: (@jumbotron-padding * 2);\n padding-right: (@jumbotron-padding * 2);\n }\n\n h1,\n .h1 {\n font-size: @jumbotron-heading-font-size;\n }\n }\n}\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n display: block;\n padding: @thumbnail-padding;\n margin-bottom: @line-height-computed;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(border .2s ease-in-out);\n\n > img,\n a > img {\n &:extend(.img-responsive);\n margin-left: auto;\n margin-right: auto;\n }\n\n // Add a hover state for linked versions only\n a&:hover,\n a&:focus,\n a&.active {\n border-color: @link-color;\n }\n\n // Image captions\n .caption {\n padding: @thumbnail-caption-padding;\n color: @thumbnail-caption-color;\n }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n padding: @alert-padding;\n margin-bottom: @line-height-computed;\n border: 1px solid transparent;\n border-radius: @alert-border-radius;\n\n // Headings for larger alerts\n h4 {\n margin-top: 0;\n // Specified for the h4 to prevent conflicts of changing @headings-color\n color: inherit;\n }\n\n // Provide class for links that match alerts\n .alert-link {\n font-weight: @alert-link-font-weight;\n }\n\n // Improve alignment and spacing of inner content\n > p,\n > ul {\n margin-bottom: 0;\n }\n\n > p + p {\n margin-top: 5px;\n }\n}\n\n// Dismissible alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.\n.alert-dismissible {\n padding-right: (@alert-padding + 20);\n\n // Adjust close link position\n .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n\n.alert-info {\n .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n\n.alert-warning {\n .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n\n.alert-danger {\n .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","// Alerts\n\n.alert-variant(@background; @border; @text-color) {\n background-color: @background;\n border-color: @border;\n color: @text-color;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n overflow: hidden;\n height: @line-height-computed;\n margin-bottom: @line-height-computed;\n background-color: @progress-bg;\n border-radius: @progress-border-radius;\n .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: @font-size-small;\n line-height: @line-height-computed;\n color: @progress-bar-color;\n text-align: center;\n background-color: @progress-bar-bg;\n .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n .transition(width .6s ease);\n}\n\n// Striped bars\n//\n// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar-striped` class, which you just add to an existing\n// `.progress-bar`.\n.progress-striped .progress-bar,\n.progress-bar-striped {\n #gradient > .striped();\n background-size: 40px 40px;\n}\n\n// Call animation for the active one\n//\n// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar.active` approach.\n.progress.active .progress-bar,\n.progress-bar.active {\n .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Progress bars\n\n.progress-bar-variant(@color) {\n background-color: @color;\n\n // Deprecated parent class requirement as of v3.2.0\n .progress-striped & {\n #gradient > .striped();\n }\n}\n",".media {\n // Proper spacing between instances of .media\n margin-top: 15px;\n\n &:first-child {\n margin-top: 0;\n }\n}\n\n.media,\n.media-body {\n zoom: 1;\n overflow: hidden;\n}\n\n.media-body {\n width: 10000px;\n}\n\n.media-object {\n display: block;\n\n // Fix collapse in webkit from max-width: 100% and display: table-cell.\n &.img-thumbnail {\n max-width: none;\n }\n}\n\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n\n.media-middle {\n vertical-align: middle;\n}\n\n.media-bottom {\n vertical-align: bottom;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n\n// Media list variation\n//\n// Undo default ul/ol styles\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on , , or .\n\n.list-group {\n // No need to set list-style: none; since .list-group-item is block level\n margin-bottom: 20px;\n padding-left: 0; // reset padding because ul and ol\n}\n\n\n// Individual list items\n//\n// Use on `li`s or `div`s within the `.list-group` parent.\n\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n // Place the border on the list items and negative margin up for better styling\n margin-bottom: -1px;\n background-color: @list-group-bg;\n border: 1px solid @list-group-border;\n\n // Round the first and last items\n &:first-child {\n .border-top-radius(@list-group-border-radius);\n }\n &:last-child {\n margin-bottom: 0;\n .border-bottom-radius(@list-group-border-radius);\n }\n}\n\n\n// Interactive list items\n//\n// Use anchor or button elements instead of `li`s or `div`s to create interactive items.\n// Includes an extra `.active` modifier class for showing selected items.\n\na.list-group-item,\nbutton.list-group-item {\n color: @list-group-link-color;\n\n .list-group-item-heading {\n color: @list-group-link-heading-color;\n }\n\n // Hover state\n &:hover,\n &:focus {\n text-decoration: none;\n color: @list-group-link-hover-color;\n background-color: @list-group-hover-bg;\n }\n}\n\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n\n.list-group-item {\n // Disabled state\n &.disabled,\n &.disabled:hover,\n &.disabled:focus {\n background-color: @list-group-disabled-bg;\n color: @list-group-disabled-color;\n cursor: @cursor-disabled;\n\n // Force color to inherit for custom content\n .list-group-item-heading {\n color: inherit;\n }\n .list-group-item-text {\n color: @list-group-disabled-text-color;\n }\n }\n\n // Active class on item itself, not parent\n &.active,\n &.active:hover,\n &.active:focus {\n z-index: 2; // Place active items above their siblings for proper border styling\n color: @list-group-active-color;\n background-color: @list-group-active-bg;\n border-color: @list-group-active-border;\n\n // Force color to inherit for custom content\n .list-group-item-heading,\n .list-group-item-heading > small,\n .list-group-item-heading > .small {\n color: inherit;\n }\n .list-group-item-text {\n color: @list-group-active-text-color;\n }\n }\n}\n\n\n// Contextual variants\n//\n// Add modifier classes to change text and background color on individual items.\n// Organizationally, this must come after the `:hover` states.\n\n.list-group-item-variant(success; @state-success-bg; @state-success-text);\n.list-group-item-variant(info; @state-info-bg; @state-info-text);\n.list-group-item-variant(warning; @state-warning-bg; @state-warning-text);\n.list-group-item-variant(danger; @state-danger-bg; @state-danger-text);\n\n\n// Custom content options\n//\n// Extra classes for creating well-formatted content within `.list-group-item`s.\n\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n","// List Groups\n\n.list-group-item-variant(@state; @background; @color) {\n .list-group-item-@{state} {\n color: @color;\n background-color: @background;\n\n a&,\n button& {\n color: @color;\n\n .list-group-item-heading {\n color: inherit;\n }\n\n &:hover,\n &:focus {\n color: @color;\n background-color: darken(@background, 5%);\n }\n &.active,\n &.active:hover,\n &.active:focus {\n color: #fff;\n background-color: @color;\n border-color: @color;\n }\n }\n }\n}\n","//\n// Panels\n// --------------------------------------------------\n\n\n// Base class\n.panel {\n margin-bottom: @line-height-computed;\n background-color: @panel-bg;\n border: 1px solid transparent;\n border-radius: @panel-border-radius;\n .box-shadow(0 1px 1px rgba(0,0,0,.05));\n}\n\n// Panel contents\n.panel-body {\n padding: @panel-body-padding;\n &:extend(.clearfix all);\n}\n\n// Optional heading\n.panel-heading {\n padding: @panel-heading-padding;\n border-bottom: 1px solid transparent;\n .border-top-radius((@panel-border-radius - 1));\n\n > .dropdown .dropdown-toggle {\n color: inherit;\n }\n}\n\n// Within heading, strip any `h*` tag of its default margins for spacing.\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: ceil((@font-size-base * 1.125));\n color: inherit;\n\n > a,\n > small,\n > .small,\n > small > a,\n > .small > a {\n color: inherit;\n }\n}\n\n// Optional footer (stays gray in every modifier class)\n.panel-footer {\n padding: @panel-footer-padding;\n background-color: @panel-footer-bg;\n border-top: 1px solid @panel-inner-border;\n .border-bottom-radius((@panel-border-radius - 1));\n}\n\n\n// List groups in panels\n//\n// By default, space out list group content from panel headings to account for\n// any kind of custom content between the two.\n\n.panel {\n > .list-group,\n > .panel-collapse > .list-group {\n margin-bottom: 0;\n\n .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n }\n\n // Add border top radius for first one\n &:first-child {\n .list-group-item:first-child {\n border-top: 0;\n .border-top-radius((@panel-border-radius - 1));\n }\n }\n\n // Add border bottom radius for last one\n &:last-child {\n .list-group-item:last-child {\n border-bottom: 0;\n .border-bottom-radius((@panel-border-radius - 1));\n }\n }\n }\n > .panel-heading + .panel-collapse > .list-group {\n .list-group-item:first-child {\n .border-top-radius(0);\n }\n }\n}\n// Collapse space between when there's no additional content.\n.panel-heading + .list-group {\n .list-group-item:first-child {\n border-top-width: 0;\n }\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n\n// Tables in panels\n//\n// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and\n// watch it go full width.\n\n.panel {\n > .table,\n > .table-responsive > .table,\n > .panel-collapse > .table {\n margin-bottom: 0;\n\n caption {\n padding-left: @panel-body-padding;\n padding-right: @panel-body-padding;\n }\n }\n // Add border top radius for first one\n > .table:first-child,\n > .table-responsive:first-child > .table:first-child {\n .border-top-radius((@panel-border-radius - 1));\n\n > thead:first-child,\n > tbody:first-child {\n > tr:first-child {\n border-top-left-radius: (@panel-border-radius - 1);\n border-top-right-radius: (@panel-border-radius - 1);\n\n td:first-child,\n th:first-child {\n border-top-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-top-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n // Add border bottom radius for last one\n > .table:last-child,\n > .table-responsive:last-child > .table:last-child {\n .border-bottom-radius((@panel-border-radius - 1));\n\n > tbody:last-child,\n > tfoot:last-child {\n > tr:last-child {\n border-bottom-left-radius: (@panel-border-radius - 1);\n border-bottom-right-radius: (@panel-border-radius - 1);\n\n td:first-child,\n th:first-child {\n border-bottom-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-bottom-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n > .panel-body + .table,\n > .panel-body + .table-responsive,\n > .table + .panel-body,\n > .table-responsive + .panel-body {\n border-top: 1px solid @table-border-color;\n }\n > .table > tbody:first-child > tr:first-child th,\n > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n }\n > .table-bordered,\n > .table-responsive > .table-bordered {\n border: 0;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n > thead,\n > tbody {\n > tr:first-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n > tbody,\n > tfoot {\n > tr:last-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n }\n > .table-responsive {\n border: 0;\n margin-bottom: 0;\n }\n}\n\n\n// Collapsable panels (aka, accordion)\n//\n// Wrap a series of panels in `.panel-group` to turn them into an accordion with\n// the help of our collapse JavaScript plugin.\n\n.panel-group {\n margin-bottom: @line-height-computed;\n\n // Tighten up margin so it's only between panels\n .panel {\n margin-bottom: 0;\n border-radius: @panel-border-radius;\n\n + .panel {\n margin-top: 5px;\n }\n }\n\n .panel-heading {\n border-bottom: 0;\n\n + .panel-collapse > .panel-body,\n + .panel-collapse > .list-group {\n border-top: 1px solid @panel-inner-border;\n }\n }\n\n .panel-footer {\n border-top: 0;\n + .panel-collapse .panel-body {\n border-bottom: 1px solid @panel-inner-border;\n }\n }\n}\n\n\n// Contextual variations\n.panel-default {\n .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);\n}\n.panel-primary {\n .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);\n}\n.panel-success {\n .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);\n}\n.panel-info {\n .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);\n}\n.panel-warning {\n .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);\n}\n.panel-danger {\n .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);\n}\n","// Panels\n\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n border-color: @border;\n\n & > .panel-heading {\n color: @heading-text-color;\n background-color: @heading-bg-color;\n border-color: @heading-border;\n\n + .panel-collapse > .panel-body {\n border-top-color: @border;\n }\n .badge {\n color: @heading-bg-color;\n background-color: @heading-text-color;\n }\n }\n & > .panel-footer {\n + .panel-collapse > .panel-body {\n border-bottom-color: @border;\n }\n }\n}\n","// Embeds responsive\n//\n// Credit: Nicolas Gallagher and SUIT CSS.\n\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n\n .embed-responsive-item,\n iframe,\n embed,\n object,\n video {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n height: 100%;\n width: 100%;\n border: 0;\n }\n}\n\n// Modifier class for 16:9 aspect ratio\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n\n// Modifier class for 4:3 aspect ratio\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n","//\n// Wells\n// --------------------------------------------------\n\n\n// Base class\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: @well-bg;\n border: 1px solid @well-border;\n border-radius: @border-radius-base;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));\n blockquote {\n border-color: #ddd;\n border-color: rgba(0,0,0,.15);\n }\n}\n\n// Sizes\n.well-lg {\n padding: 24px;\n border-radius: @border-radius-large;\n}\n.well-sm {\n padding: 9px;\n border-radius: @border-radius-small;\n}\n","//\n// Close icons\n// --------------------------------------------------\n\n\n.close {\n float: right;\n font-size: (@font-size-base * 1.5);\n font-weight: @close-font-weight;\n line-height: 1;\n color: @close-color;\n text-shadow: @close-text-shadow;\n .opacity(.2);\n\n &:hover,\n &:focus {\n color: @close-color;\n text-decoration: none;\n cursor: pointer;\n .opacity(.5);\n }\n\n // Additional properties for button version\n // iOS requires the button element instead of an anchor tag.\n // If you want the anchor version, it requires `href=\"#\"`.\n // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n button& {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n }\n}\n","//\n// Modals\n// --------------------------------------------------\n\n// .modal-open - body class for killing the scroll\n// .modal - container to scroll within\n// .modal-dialog - positioning shell for the actual modal\n// .modal-content - actual modal w/ bg and corners and shit\n\n// Kill the scroll on the body\n.modal-open {\n overflow: hidden;\n}\n\n// Container that the modal scrolls within\n.modal {\n display: none;\n overflow: hidden;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal;\n -webkit-overflow-scrolling: touch;\n\n // Prevent Chrome on Windows from adding a focus outline. For details, see\n // https://github.com/twbs/bootstrap/pull/10951.\n outline: 0;\n\n // When fading in the modal, animate it to slide down\n &.fade .modal-dialog {\n .translate(0, -25%);\n .transition-transform(~\"0.3s ease-out\");\n }\n &.in .modal-dialog { .translate(0, 0) }\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n// Shell div to position the modal with bottom padding\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n\n// Actual modal\n.modal-content {\n position: relative;\n background-color: @modal-content-bg;\n border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)\n border: 1px solid @modal-content-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 3px 9px rgba(0,0,0,.5));\n background-clip: padding-box;\n // Remove focus outline from opened modal\n outline: 0;\n}\n\n// Modal background\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal-background;\n background-color: @modal-backdrop-bg;\n // Fade for backdrop\n &.fade { .opacity(0); }\n &.in { .opacity(@modal-backdrop-opacity); }\n}\n\n// Modal header\n// Top section of the modal w/ title and dismiss\n.modal-header {\n padding: @modal-title-padding;\n border-bottom: 1px solid @modal-header-border-color;\n min-height: (@modal-title-padding + @modal-title-line-height);\n}\n// Close icon\n.modal-header .close {\n margin-top: -2px;\n}\n\n// Title text within header\n.modal-title {\n margin: 0;\n line-height: @modal-title-line-height;\n}\n\n// Modal body\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\n.modal-body {\n position: relative;\n padding: @modal-inner-padding;\n}\n\n// Footer (for actions)\n.modal-footer {\n padding: @modal-inner-padding;\n text-align: right; // right align buttons\n border-top: 1px solid @modal-footer-border-color;\n &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons\n\n // Properly space out buttons\n .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0; // account for input[type=\"submit\"] which gets the bottom margin like all other inputs\n }\n // but override that for button groups\n .btn-group .btn + .btn {\n margin-left: -1px;\n }\n // and override it for block buttons as well\n .btn-block + .btn-block {\n margin-left: 0;\n }\n}\n\n// Measure scrollbar width for padding body during modal show/hide\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n\n// Scale up the modal\n@media (min-width: @screen-sm-min) {\n // Automatically set modal's width for larger viewports\n .modal-dialog {\n width: @modal-md;\n margin: 30px auto;\n }\n .modal-content {\n .box-shadow(0 5px 15px rgba(0,0,0,.5));\n }\n\n // Modal sizes\n .modal-sm { width: @modal-sm; }\n}\n\n@media (min-width: @screen-md-min) {\n .modal-lg { width: @modal-lg; }\n}\n","//\n// Tooltips\n// --------------------------------------------------\n\n\n// Base class\n.tooltip {\n position: absolute;\n z-index: @zindex-tooltip;\n display: block;\n // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.\n // So reset our font and text properties to avoid inheriting weird values.\n .reset-text();\n font-size: @font-size-small;\n\n .opacity(0);\n\n &.in { .opacity(@tooltip-opacity); }\n &.top { margin-top: -3px; padding: @tooltip-arrow-width 0; }\n &.right { margin-left: 3px; padding: 0 @tooltip-arrow-width; }\n &.bottom { margin-top: 3px; padding: @tooltip-arrow-width 0; }\n &.left { margin-left: -3px; padding: 0 @tooltip-arrow-width; }\n}\n\n// Wrapper for the tooltip content\n.tooltip-inner {\n max-width: @tooltip-max-width;\n padding: 3px 8px;\n color: @tooltip-color;\n text-align: center;\n background-color: @tooltip-bg;\n border-radius: @border-radius-base;\n}\n\n// Arrows\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1\n.tooltip {\n &.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-left .tooltip-arrow {\n bottom: 0;\n right: @tooltip-arrow-width;\n margin-bottom: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-right .tooltip-arrow {\n bottom: 0;\n left: @tooltip-arrow-width;\n margin-bottom: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;\n border-right-color: @tooltip-arrow-color;\n }\n &.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-left-color: @tooltip-arrow-color;\n }\n &.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-left .tooltip-arrow {\n top: 0;\n right: @tooltip-arrow-width;\n margin-top: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-right .tooltip-arrow {\n top: 0;\n left: @tooltip-arrow-width;\n margin-top: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n}\n",".reset-text() {\n font-family: @font-family-base;\n // We deliberately do NOT reset font-size.\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: @line-height-base;\n text-align: left; // Fallback for where `start` is not supported\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n}\n","//\n// Popovers\n// --------------------------------------------------\n\n\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: @zindex-popover;\n display: none;\n max-width: @popover-max-width;\n padding: 1px;\n // Our parent element can be arbitrary since popovers are by default inserted as a sibling of their target element.\n // So reset our font and text properties to avoid inheriting weird values.\n .reset-text();\n font-size: @font-size-base;\n\n background-color: @popover-bg;\n background-clip: padding-box;\n border: 1px solid @popover-fallback-border-color;\n border: 1px solid @popover-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 5px 10px rgba(0,0,0,.2));\n\n // Offset the popover to account for the popover arrow\n &.top { margin-top: -@popover-arrow-width; }\n &.right { margin-left: @popover-arrow-width; }\n &.bottom { margin-top: @popover-arrow-width; }\n &.left { margin-left: -@popover-arrow-width; }\n}\n\n.popover-title {\n margin: 0; // reset heading margin\n padding: 8px 14px;\n font-size: @font-size-base;\n background-color: @popover-title-bg;\n border-bottom: 1px solid darken(@popover-title-bg, 5%);\n border-radius: (@border-radius-large - 1) (@border-radius-large - 1) 0 0;\n}\n\n.popover-content {\n padding: 9px 14px;\n}\n\n// Arrows\n//\n// .arrow is outer, .arrow:after is inner\n\n.popover > .arrow {\n &,\n &:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n }\n}\n.popover > .arrow {\n border-width: @popover-arrow-outer-width;\n}\n.popover > .arrow:after {\n border-width: @popover-arrow-width;\n content: \"\";\n}\n\n.popover {\n &.top > .arrow {\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-bottom-width: 0;\n border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-top-color: @popover-arrow-outer-color;\n bottom: -@popover-arrow-outer-width;\n &:after {\n content: \" \";\n bottom: 1px;\n margin-left: -@popover-arrow-width;\n border-bottom-width: 0;\n border-top-color: @popover-arrow-color;\n }\n }\n &.right > .arrow {\n top: 50%;\n left: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-left-width: 0;\n border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-right-color: @popover-arrow-outer-color;\n &:after {\n content: \" \";\n left: 1px;\n bottom: -@popover-arrow-width;\n border-left-width: 0;\n border-right-color: @popover-arrow-color;\n }\n }\n &.bottom > .arrow {\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-bottom-color: @popover-arrow-outer-color;\n top: -@popover-arrow-outer-width;\n &:after {\n content: \" \";\n top: 1px;\n margin-left: -@popover-arrow-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-color;\n }\n }\n\n &.left > .arrow {\n top: 50%;\n right: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-right-width: 0;\n border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-left-color: @popover-arrow-outer-color;\n &:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: @popover-arrow-color;\n bottom: -@popover-arrow-width;\n }\n }\n}\n","//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n position: relative;\n}\n\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n\n > .item {\n display: none;\n position: relative;\n .transition(.6s ease-in-out left);\n\n // Account for jankitude on images\n > img,\n > a > img {\n &:extend(.img-responsive);\n line-height: 1;\n }\n\n // WebKit CSS3 transforms for supported devices\n @media all and (transform-3d), (-webkit-transform-3d) {\n .transition-transform(~'0.6s ease-in-out');\n .backface-visibility(~'hidden');\n .perspective(1000px);\n\n &.next,\n &.active.right {\n .translate3d(100%, 0, 0);\n left: 0;\n }\n &.prev,\n &.active.left {\n .translate3d(-100%, 0, 0);\n left: 0;\n }\n &.next.left,\n &.prev.right,\n &.active {\n .translate3d(0, 0, 0);\n left: 0;\n }\n }\n }\n\n > .active,\n > .next,\n > .prev {\n display: block;\n }\n\n > .active {\n left: 0;\n }\n\n > .next,\n > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n }\n\n > .next {\n left: 100%;\n }\n > .prev {\n left: -100%;\n }\n > .next.left,\n > .prev.right {\n left: 0;\n }\n\n > .active.left {\n left: -100%;\n }\n > .active.right {\n left: 100%;\n }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: @carousel-control-width;\n .opacity(@carousel-control-opacity);\n font-size: @carousel-control-font-size;\n color: @carousel-control-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n // We can't have this transition here because WebKit cancels the carousel\n // animation if you trip this while in the middle of another animation.\n\n // Set gradients for backgrounds\n &.left {\n #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));\n }\n &.right {\n left: auto;\n right: 0;\n #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));\n }\n\n // Hover/focus state\n &:hover,\n &:focus {\n outline: 0;\n color: @carousel-control-color;\n text-decoration: none;\n .opacity(.9);\n }\n\n // Toggles\n .icon-prev,\n .icon-next,\n .glyphicon-chevron-left,\n .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n margin-top: -10px;\n z-index: 5;\n display: inline-block;\n }\n .icon-prev,\n .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n }\n .icon-next,\n .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n }\n .icon-prev,\n .icon-next {\n width: 20px;\n height: 20px;\n line-height: 1;\n font-family: serif;\n }\n\n\n .icon-prev {\n &:before {\n content: '\\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n }\n }\n .icon-next {\n &:before {\n content: '\\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n }\n }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n\n li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid @carousel-indicator-border-color;\n border-radius: 10px;\n cursor: pointer;\n\n // IE8-9 hack for event handling\n //\n // Internet Explorer 8-9 does not support clicks on elements without a set\n // `background-color`. We cannot use `filter` since that's not viewed as a\n // background color by the browser. Thus, a hack is needed.\n // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer\n //\n // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n // set alpha transparency for the best results possible.\n background-color: #000 \\9; // IE8\n background-color: rgba(0,0,0,0); // IE9\n }\n .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: @carousel-indicator-active-bg;\n }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: @carousel-caption-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n & .btn {\n text-shadow: none; // No shadow for button elements in carousel-caption\n }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n // Scale up the controls a smidge\n .carousel-control {\n .glyphicon-chevron-left,\n .glyphicon-chevron-right,\n .icon-prev,\n .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -15px;\n font-size: 30px;\n }\n .glyphicon-chevron-left,\n .icon-prev {\n margin-left: -15px;\n }\n .glyphicon-chevron-right,\n .icon-next {\n margin-right: -15px;\n }\n }\n\n // Show and left align the captions\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n\n // Move up the indicators\n .carousel-indicators {\n bottom: 20px;\n }\n}\n","// Clearfix\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n// contenteditable attribute is included anywhere else in the document.\n// Otherwise it causes space to appear at the top and bottom of elements\n// that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n// `:before` to contain the top-margins of child elements.\n//\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n\n.clearfix() {\n &:before,\n &:after {\n content: \" \"; // 1\n display: table; // 2\n }\n &:after {\n clear: both;\n }\n}\n","// Center-align a block level element\n\n.center-block() {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n","// CSS image replacement\n//\n// Heads up! v3 launched with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n font: ~\"0/0\" a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n\n// New mixin to use as of v3.0.1\n.text-hide() {\n .hide-text();\n}\n","//\n// Responsive: Utility classes\n// --------------------------------------------------\n\n\n// IE10 in Windows (Phone) 8\n//\n// Support for responsive views via media queries is kind of borked in IE10, for\n// Surface/desktop in split view and for Windows Phone 8. This particular fix\n// must be accompanied by a snippet of JavaScript to sniff the user agent and\n// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at\n// our Getting Started page for more information on this bug.\n//\n// For more information, see the following:\n//\n// Issue: https://github.com/twbs/bootstrap/issues/10497\n// Docs: http://getbootstrap.com/getting-started/#support-ie10-width\n// Source: http://timkadlec.com/2013/01/windows-phone-8-and-device-width/\n// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/\n\n@-ms-viewport {\n width: device-width;\n}\n\n\n// Visibility utilities\n// Note: Deprecated .visible-xs, .visible-sm, .visible-md, and .visible-lg as of v3.2.0\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n .responsive-invisibility();\n}\n\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n\n.visible-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-visibility();\n }\n}\n.visible-xs-block {\n @media (max-width: @screen-xs-max) {\n display: block !important;\n }\n}\n.visible-xs-inline {\n @media (max-width: @screen-xs-max) {\n display: inline !important;\n }\n}\n.visible-xs-inline-block {\n @media (max-width: @screen-xs-max) {\n display: inline-block !important;\n }\n}\n\n.visible-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-visibility();\n }\n}\n.visible-sm-block {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: block !important;\n }\n}\n.visible-sm-inline {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: inline !important;\n }\n}\n.visible-sm-inline-block {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: inline-block !important;\n }\n}\n\n.visible-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-visibility();\n }\n}\n.visible-md-block {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: block !important;\n }\n}\n.visible-md-inline {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: inline !important;\n }\n}\n.visible-md-inline-block {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: inline-block !important;\n }\n}\n\n.visible-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-visibility();\n }\n}\n.visible-lg-block {\n @media (min-width: @screen-lg-min) {\n display: block !important;\n }\n}\n.visible-lg-inline {\n @media (min-width: @screen-lg-min) {\n display: inline !important;\n }\n}\n.visible-lg-inline-block {\n @media (min-width: @screen-lg-min) {\n display: inline-block !important;\n }\n}\n\n.hidden-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-invisibility();\n }\n}\n.hidden-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-invisibility();\n }\n}\n.hidden-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-invisibility();\n }\n}\n.hidden-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-invisibility();\n }\n}\n\n\n// Print utilities\n//\n// Media queries are placed on the inside to be mixin-friendly.\n\n// Note: Deprecated .visible-print as of v3.2.0\n.visible-print {\n .responsive-invisibility();\n\n @media print {\n .responsive-visibility();\n }\n}\n.visible-print-block {\n display: none !important;\n\n @media print {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n\n @media print {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n\n @media print {\n display: inline-block !important;\n }\n}\n\n.hidden-print {\n @media print {\n .responsive-invisibility();\n }\n}\n","// Responsive utilities\n\n//\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n display: block !important;\n table& { display: table !important; }\n tr& { display: table-row !important; }\n th&,\n td& { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n display: none !important;\n}\n"]}
\ No newline at end of file
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap.min.css b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap.min.css
new file mode 100644
index 00000000..d65c66b1
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/css/bootstrap.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}
\ No newline at end of file
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.eot b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 00000000..b93a4953
Binary files /dev/null and b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.eot differ
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.svg b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 00000000..94fb5490
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,288 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.ttf b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 00000000..1413fc60
Binary files /dev/null and b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.ttf differ
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.woff b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 00000000..9e612858
Binary files /dev/null and b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.woff differ
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.woff2 b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.woff2
new file mode 100644
index 00000000..64539b54
Binary files /dev/null and b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/fonts/glyphicons-halflings-regular.woff2 differ
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/js/bootstrap.js b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/js/bootstrap.js
new file mode 100644
index 00000000..5debfd7d
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/js/bootstrap.js
@@ -0,0 +1,2363 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under the MIT license
+ */
+
+if (typeof jQuery === 'undefined') {
+ throw new Error('Bootstrap\'s JavaScript requires jQuery')
+}
+
++function ($) {
+ 'use strict';
+ var version = $.fn.jquery.split(' ')[0].split('.')
+ if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {
+ throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher')
+ }
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: transition.js v3.3.5
+ * http://getbootstrap.com/javascript/#transitions
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
+ // ============================================================
+
+ function transitionEnd() {
+ var el = document.createElement('bootstrap')
+
+ var transEndEventNames = {
+ WebkitTransition : 'webkitTransitionEnd',
+ MozTransition : 'transitionend',
+ OTransition : 'oTransitionEnd otransitionend',
+ transition : 'transitionend'
+ }
+
+ for (var name in transEndEventNames) {
+ if (el.style[name] !== undefined) {
+ return { end: transEndEventNames[name] }
+ }
+ }
+
+ return false // explicit for ie8 ( ._.)
+ }
+
+ // http://blog.alexmaccaw.com/css-transitions
+ $.fn.emulateTransitionEnd = function (duration) {
+ var called = false
+ var $el = this
+ $(this).one('bsTransitionEnd', function () { called = true })
+ var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
+ setTimeout(callback, duration)
+ return this
+ }
+
+ $(function () {
+ $.support.transition = transitionEnd()
+
+ if (!$.support.transition) return
+
+ $.event.special.bsTransitionEnd = {
+ bindType: $.support.transition.end,
+ delegateType: $.support.transition.end,
+ handle: function (e) {
+ if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
+ }
+ }
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: alert.js v3.3.5
+ * http://getbootstrap.com/javascript/#alerts
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // ALERT CLASS DEFINITION
+ // ======================
+
+ var dismiss = '[data-dismiss="alert"]'
+ var Alert = function (el) {
+ $(el).on('click', dismiss, this.close)
+ }
+
+ Alert.VERSION = '3.3.5'
+
+ Alert.TRANSITION_DURATION = 150
+
+ Alert.prototype.close = function (e) {
+ var $this = $(this)
+ var selector = $this.attr('data-target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ }
+
+ var $parent = $(selector)
+
+ if (e) e.preventDefault()
+
+ if (!$parent.length) {
+ $parent = $this.closest('.alert')
+ }
+
+ $parent.trigger(e = $.Event('close.bs.alert'))
+
+ if (e.isDefaultPrevented()) return
+
+ $parent.removeClass('in')
+
+ function removeElement() {
+ // detach from parent, fire event then clean up data
+ $parent.detach().trigger('closed.bs.alert').remove()
+ }
+
+ $.support.transition && $parent.hasClass('fade') ?
+ $parent
+ .one('bsTransitionEnd', removeElement)
+ .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
+ removeElement()
+ }
+
+
+ // ALERT PLUGIN DEFINITION
+ // =======================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.alert')
+
+ if (!data) $this.data('bs.alert', (data = new Alert(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ var old = $.fn.alert
+
+ $.fn.alert = Plugin
+ $.fn.alert.Constructor = Alert
+
+
+ // ALERT NO CONFLICT
+ // =================
+
+ $.fn.alert.noConflict = function () {
+ $.fn.alert = old
+ return this
+ }
+
+
+ // ALERT DATA-API
+ // ==============
+
+ $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: button.js v3.3.5
+ * http://getbootstrap.com/javascript/#buttons
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // BUTTON PUBLIC CLASS DEFINITION
+ // ==============================
+
+ var Button = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, Button.DEFAULTS, options)
+ this.isLoading = false
+ }
+
+ Button.VERSION = '3.3.5'
+
+ Button.DEFAULTS = {
+ loadingText: 'loading...'
+ }
+
+ Button.prototype.setState = function (state) {
+ var d = 'disabled'
+ var $el = this.$element
+ var val = $el.is('input') ? 'val' : 'html'
+ var data = $el.data()
+
+ state += 'Text'
+
+ if (data.resetText == null) $el.data('resetText', $el[val]())
+
+ // push to event loop to allow forms to submit
+ setTimeout($.proxy(function () {
+ $el[val](data[state] == null ? this.options[state] : data[state])
+
+ if (state == 'loadingText') {
+ this.isLoading = true
+ $el.addClass(d).attr(d, d)
+ } else if (this.isLoading) {
+ this.isLoading = false
+ $el.removeClass(d).removeAttr(d)
+ }
+ }, this), 0)
+ }
+
+ Button.prototype.toggle = function () {
+ var changed = true
+ var $parent = this.$element.closest('[data-toggle="buttons"]')
+
+ if ($parent.length) {
+ var $input = this.$element.find('input')
+ if ($input.prop('type') == 'radio') {
+ if ($input.prop('checked')) changed = false
+ $parent.find('.active').removeClass('active')
+ this.$element.addClass('active')
+ } else if ($input.prop('type') == 'checkbox') {
+ if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
+ this.$element.toggleClass('active')
+ }
+ $input.prop('checked', this.$element.hasClass('active'))
+ if (changed) $input.trigger('change')
+ } else {
+ this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
+ this.$element.toggleClass('active')
+ }
+ }
+
+
+ // BUTTON PLUGIN DEFINITION
+ // ========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.button')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.button', (data = new Button(this, options)))
+
+ if (option == 'toggle') data.toggle()
+ else if (option) data.setState(option)
+ })
+ }
+
+ var old = $.fn.button
+
+ $.fn.button = Plugin
+ $.fn.button.Constructor = Button
+
+
+ // BUTTON NO CONFLICT
+ // ==================
+
+ $.fn.button.noConflict = function () {
+ $.fn.button = old
+ return this
+ }
+
+
+ // BUTTON DATA-API
+ // ===============
+
+ $(document)
+ .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+ var $btn = $(e.target)
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+ Plugin.call($btn, 'toggle')
+ if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault()
+ })
+ .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+ $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: carousel.js v3.3.5
+ * http://getbootstrap.com/javascript/#carousel
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // CAROUSEL CLASS DEFINITION
+ // =========================
+
+ var Carousel = function (element, options) {
+ this.$element = $(element)
+ this.$indicators = this.$element.find('.carousel-indicators')
+ this.options = options
+ this.paused = null
+ this.sliding = null
+ this.interval = null
+ this.$active = null
+ this.$items = null
+
+ this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
+
+ this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
+ .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
+ .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
+ }
+
+ Carousel.VERSION = '3.3.5'
+
+ Carousel.TRANSITION_DURATION = 600
+
+ Carousel.DEFAULTS = {
+ interval: 5000,
+ pause: 'hover',
+ wrap: true,
+ keyboard: true
+ }
+
+ Carousel.prototype.keydown = function (e) {
+ if (/input|textarea/i.test(e.target.tagName)) return
+ switch (e.which) {
+ case 37: this.prev(); break
+ case 39: this.next(); break
+ default: return
+ }
+
+ e.preventDefault()
+ }
+
+ Carousel.prototype.cycle = function (e) {
+ e || (this.paused = false)
+
+ this.interval && clearInterval(this.interval)
+
+ this.options.interval
+ && !this.paused
+ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
+
+ return this
+ }
+
+ Carousel.prototype.getItemIndex = function (item) {
+ this.$items = item.parent().children('.item')
+ return this.$items.index(item || this.$active)
+ }
+
+ Carousel.prototype.getItemForDirection = function (direction, active) {
+ var activeIndex = this.getItemIndex(active)
+ var willWrap = (direction == 'prev' && activeIndex === 0)
+ || (direction == 'next' && activeIndex == (this.$items.length - 1))
+ if (willWrap && !this.options.wrap) return active
+ var delta = direction == 'prev' ? -1 : 1
+ var itemIndex = (activeIndex + delta) % this.$items.length
+ return this.$items.eq(itemIndex)
+ }
+
+ Carousel.prototype.to = function (pos) {
+ var that = this
+ var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
+
+ if (pos > (this.$items.length - 1) || pos < 0) return
+
+ if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
+ if (activeIndex == pos) return this.pause().cycle()
+
+ return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
+ }
+
+ Carousel.prototype.pause = function (e) {
+ e || (this.paused = true)
+
+ if (this.$element.find('.next, .prev').length && $.support.transition) {
+ this.$element.trigger($.support.transition.end)
+ this.cycle(true)
+ }
+
+ this.interval = clearInterval(this.interval)
+
+ return this
+ }
+
+ Carousel.prototype.next = function () {
+ if (this.sliding) return
+ return this.slide('next')
+ }
+
+ Carousel.prototype.prev = function () {
+ if (this.sliding) return
+ return this.slide('prev')
+ }
+
+ Carousel.prototype.slide = function (type, next) {
+ var $active = this.$element.find('.item.active')
+ var $next = next || this.getItemForDirection(type, $active)
+ var isCycling = this.interval
+ var direction = type == 'next' ? 'left' : 'right'
+ var that = this
+
+ if ($next.hasClass('active')) return (this.sliding = false)
+
+ var relatedTarget = $next[0]
+ var slideEvent = $.Event('slide.bs.carousel', {
+ relatedTarget: relatedTarget,
+ direction: direction
+ })
+ this.$element.trigger(slideEvent)
+ if (slideEvent.isDefaultPrevented()) return
+
+ this.sliding = true
+
+ isCycling && this.pause()
+
+ if (this.$indicators.length) {
+ this.$indicators.find('.active').removeClass('active')
+ var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
+ $nextIndicator && $nextIndicator.addClass('active')
+ }
+
+ var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
+ if ($.support.transition && this.$element.hasClass('slide')) {
+ $next.addClass(type)
+ $next[0].offsetWidth // force reflow
+ $active.addClass(direction)
+ $next.addClass(direction)
+ $active
+ .one('bsTransitionEnd', function () {
+ $next.removeClass([type, direction].join(' ')).addClass('active')
+ $active.removeClass(['active', direction].join(' '))
+ that.sliding = false
+ setTimeout(function () {
+ that.$element.trigger(slidEvent)
+ }, 0)
+ })
+ .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
+ } else {
+ $active.removeClass('active')
+ $next.addClass('active')
+ this.sliding = false
+ this.$element.trigger(slidEvent)
+ }
+
+ isCycling && this.cycle()
+
+ return this
+ }
+
+
+ // CAROUSEL PLUGIN DEFINITION
+ // ==========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.carousel')
+ var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
+ var action = typeof option == 'string' ? option : options.slide
+
+ if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
+ if (typeof option == 'number') data.to(option)
+ else if (action) data[action]()
+ else if (options.interval) data.pause().cycle()
+ })
+ }
+
+ var old = $.fn.carousel
+
+ $.fn.carousel = Plugin
+ $.fn.carousel.Constructor = Carousel
+
+
+ // CAROUSEL NO CONFLICT
+ // ====================
+
+ $.fn.carousel.noConflict = function () {
+ $.fn.carousel = old
+ return this
+ }
+
+
+ // CAROUSEL DATA-API
+ // =================
+
+ var clickHandler = function (e) {
+ var href
+ var $this = $(this)
+ var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
+ if (!$target.hasClass('carousel')) return
+ var options = $.extend({}, $target.data(), $this.data())
+ var slideIndex = $this.attr('data-slide-to')
+ if (slideIndex) options.interval = false
+
+ Plugin.call($target, options)
+
+ if (slideIndex) {
+ $target.data('bs.carousel').to(slideIndex)
+ }
+
+ e.preventDefault()
+ }
+
+ $(document)
+ .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
+ .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
+
+ $(window).on('load', function () {
+ $('[data-ride="carousel"]').each(function () {
+ var $carousel = $(this)
+ Plugin.call($carousel, $carousel.data())
+ })
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: collapse.js v3.3.5
+ * http://getbootstrap.com/javascript/#collapse
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // COLLAPSE PUBLIC CLASS DEFINITION
+ // ================================
+
+ var Collapse = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, Collapse.DEFAULTS, options)
+ this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
+ '[data-toggle="collapse"][data-target="#' + element.id + '"]')
+ this.transitioning = null
+
+ if (this.options.parent) {
+ this.$parent = this.getParent()
+ } else {
+ this.addAriaAndCollapsedClass(this.$element, this.$trigger)
+ }
+
+ if (this.options.toggle) this.toggle()
+ }
+
+ Collapse.VERSION = '3.3.5'
+
+ Collapse.TRANSITION_DURATION = 350
+
+ Collapse.DEFAULTS = {
+ toggle: true
+ }
+
+ Collapse.prototype.dimension = function () {
+ var hasWidth = this.$element.hasClass('width')
+ return hasWidth ? 'width' : 'height'
+ }
+
+ Collapse.prototype.show = function () {
+ if (this.transitioning || this.$element.hasClass('in')) return
+
+ var activesData
+ var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
+
+ if (actives && actives.length) {
+ activesData = actives.data('bs.collapse')
+ if (activesData && activesData.transitioning) return
+ }
+
+ var startEvent = $.Event('show.bs.collapse')
+ this.$element.trigger(startEvent)
+ if (startEvent.isDefaultPrevented()) return
+
+ if (actives && actives.length) {
+ Plugin.call(actives, 'hide')
+ activesData || actives.data('bs.collapse', null)
+ }
+
+ var dimension = this.dimension()
+
+ this.$element
+ .removeClass('collapse')
+ .addClass('collapsing')[dimension](0)
+ .attr('aria-expanded', true)
+
+ this.$trigger
+ .removeClass('collapsed')
+ .attr('aria-expanded', true)
+
+ this.transitioning = 1
+
+ var complete = function () {
+ this.$element
+ .removeClass('collapsing')
+ .addClass('collapse in')[dimension]('')
+ this.transitioning = 0
+ this.$element
+ .trigger('shown.bs.collapse')
+ }
+
+ if (!$.support.transition) return complete.call(this)
+
+ var scrollSize = $.camelCase(['scroll', dimension].join('-'))
+
+ this.$element
+ .one('bsTransitionEnd', $.proxy(complete, this))
+ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
+ }
+
+ Collapse.prototype.hide = function () {
+ if (this.transitioning || !this.$element.hasClass('in')) return
+
+ var startEvent = $.Event('hide.bs.collapse')
+ this.$element.trigger(startEvent)
+ if (startEvent.isDefaultPrevented()) return
+
+ var dimension = this.dimension()
+
+ this.$element[dimension](this.$element[dimension]())[0].offsetHeight
+
+ this.$element
+ .addClass('collapsing')
+ .removeClass('collapse in')
+ .attr('aria-expanded', false)
+
+ this.$trigger
+ .addClass('collapsed')
+ .attr('aria-expanded', false)
+
+ this.transitioning = 1
+
+ var complete = function () {
+ this.transitioning = 0
+ this.$element
+ .removeClass('collapsing')
+ .addClass('collapse')
+ .trigger('hidden.bs.collapse')
+ }
+
+ if (!$.support.transition) return complete.call(this)
+
+ this.$element
+ [dimension](0)
+ .one('bsTransitionEnd', $.proxy(complete, this))
+ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
+ }
+
+ Collapse.prototype.toggle = function () {
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
+ }
+
+ Collapse.prototype.getParent = function () {
+ return $(this.options.parent)
+ .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
+ .each($.proxy(function (i, element) {
+ var $element = $(element)
+ this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
+ }, this))
+ .end()
+ }
+
+ Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
+ var isOpen = $element.hasClass('in')
+
+ $element.attr('aria-expanded', isOpen)
+ $trigger
+ .toggleClass('collapsed', !isOpen)
+ .attr('aria-expanded', isOpen)
+ }
+
+ function getTargetFromTrigger($trigger) {
+ var href
+ var target = $trigger.attr('data-target')
+ || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
+
+ return $(target)
+ }
+
+
+ // COLLAPSE PLUGIN DEFINITION
+ // ==========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.collapse')
+ var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+ if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
+ if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.collapse
+
+ $.fn.collapse = Plugin
+ $.fn.collapse.Constructor = Collapse
+
+
+ // COLLAPSE NO CONFLICT
+ // ====================
+
+ $.fn.collapse.noConflict = function () {
+ $.fn.collapse = old
+ return this
+ }
+
+
+ // COLLAPSE DATA-API
+ // =================
+
+ $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
+ var $this = $(this)
+
+ if (!$this.attr('data-target')) e.preventDefault()
+
+ var $target = getTargetFromTrigger($this)
+ var data = $target.data('bs.collapse')
+ var option = data ? 'toggle' : $this.data()
+
+ Plugin.call($target, option)
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: dropdown.js v3.3.5
+ * http://getbootstrap.com/javascript/#dropdowns
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // DROPDOWN CLASS DEFINITION
+ // =========================
+
+ var backdrop = '.dropdown-backdrop'
+ var toggle = '[data-toggle="dropdown"]'
+ var Dropdown = function (element) {
+ $(element).on('click.bs.dropdown', this.toggle)
+ }
+
+ Dropdown.VERSION = '3.3.5'
+
+ function getParent($this) {
+ var selector = $this.attr('data-target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ }
+
+ var $parent = selector && $(selector)
+
+ return $parent && $parent.length ? $parent : $this.parent()
+ }
+
+ function clearMenus(e) {
+ if (e && e.which === 3) return
+ $(backdrop).remove()
+ $(toggle).each(function () {
+ var $this = $(this)
+ var $parent = getParent($this)
+ var relatedTarget = { relatedTarget: this }
+
+ if (!$parent.hasClass('open')) return
+
+ if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
+
+ $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
+
+ if (e.isDefaultPrevented()) return
+
+ $this.attr('aria-expanded', 'false')
+ $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
+ })
+ }
+
+ Dropdown.prototype.toggle = function (e) {
+ var $this = $(this)
+
+ if ($this.is('.disabled, :disabled')) return
+
+ var $parent = getParent($this)
+ var isActive = $parent.hasClass('open')
+
+ clearMenus()
+
+ if (!isActive) {
+ if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
+ // if mobile we use a backdrop because click events don't delegate
+ $(document.createElement('div'))
+ .addClass('dropdown-backdrop')
+ .insertAfter($(this))
+ .on('click', clearMenus)
+ }
+
+ var relatedTarget = { relatedTarget: this }
+ $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
+
+ if (e.isDefaultPrevented()) return
+
+ $this
+ .trigger('focus')
+ .attr('aria-expanded', 'true')
+
+ $parent
+ .toggleClass('open')
+ .trigger('shown.bs.dropdown', relatedTarget)
+ }
+
+ return false
+ }
+
+ Dropdown.prototype.keydown = function (e) {
+ if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
+
+ var $this = $(this)
+
+ e.preventDefault()
+ e.stopPropagation()
+
+ if ($this.is('.disabled, :disabled')) return
+
+ var $parent = getParent($this)
+ var isActive = $parent.hasClass('open')
+
+ if (!isActive && e.which != 27 || isActive && e.which == 27) {
+ if (e.which == 27) $parent.find(toggle).trigger('focus')
+ return $this.trigger('click')
+ }
+
+ var desc = ' li:not(.disabled):visible a'
+ var $items = $parent.find('.dropdown-menu' + desc)
+
+ if (!$items.length) return
+
+ var index = $items.index(e.target)
+
+ if (e.which == 38 && index > 0) index-- // up
+ if (e.which == 40 && index < $items.length - 1) index++ // down
+ if (!~index) index = 0
+
+ $items.eq(index).trigger('focus')
+ }
+
+
+ // DROPDOWN PLUGIN DEFINITION
+ // ==========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.dropdown')
+
+ if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ var old = $.fn.dropdown
+
+ $.fn.dropdown = Plugin
+ $.fn.dropdown.Constructor = Dropdown
+
+
+ // DROPDOWN NO CONFLICT
+ // ====================
+
+ $.fn.dropdown.noConflict = function () {
+ $.fn.dropdown = old
+ return this
+ }
+
+
+ // APPLY TO STANDARD DROPDOWN ELEMENTS
+ // ===================================
+
+ $(document)
+ .on('click.bs.dropdown.data-api', clearMenus)
+ .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+ .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+ .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
+ .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: modal.js v3.3.5
+ * http://getbootstrap.com/javascript/#modals
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // MODAL CLASS DEFINITION
+ // ======================
+
+ var Modal = function (element, options) {
+ this.options = options
+ this.$body = $(document.body)
+ this.$element = $(element)
+ this.$dialog = this.$element.find('.modal-dialog')
+ this.$backdrop = null
+ this.isShown = null
+ this.originalBodyPad = null
+ this.scrollbarWidth = 0
+ this.ignoreBackdropClick = false
+
+ if (this.options.remote) {
+ this.$element
+ .find('.modal-content')
+ .load(this.options.remote, $.proxy(function () {
+ this.$element.trigger('loaded.bs.modal')
+ }, this))
+ }
+ }
+
+ Modal.VERSION = '3.3.5'
+
+ Modal.TRANSITION_DURATION = 300
+ Modal.BACKDROP_TRANSITION_DURATION = 150
+
+ Modal.DEFAULTS = {
+ backdrop: true,
+ keyboard: true,
+ show: true
+ }
+
+ Modal.prototype.toggle = function (_relatedTarget) {
+ return this.isShown ? this.hide() : this.show(_relatedTarget)
+ }
+
+ Modal.prototype.show = function (_relatedTarget) {
+ var that = this
+ var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
+
+ this.$element.trigger(e)
+
+ if (this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = true
+
+ this.checkScrollbar()
+ this.setScrollbar()
+ this.$body.addClass('modal-open')
+
+ this.escape()
+ this.resize()
+
+ this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
+
+ this.$dialog.on('mousedown.dismiss.bs.modal', function () {
+ that.$element.one('mouseup.dismiss.bs.modal', function (e) {
+ if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
+ })
+ })
+
+ this.backdrop(function () {
+ var transition = $.support.transition && that.$element.hasClass('fade')
+
+ if (!that.$element.parent().length) {
+ that.$element.appendTo(that.$body) // don't move modals dom position
+ }
+
+ that.$element
+ .show()
+ .scrollTop(0)
+
+ that.adjustDialog()
+
+ if (transition) {
+ that.$element[0].offsetWidth // force reflow
+ }
+
+ that.$element.addClass('in')
+
+ that.enforceFocus()
+
+ var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
+
+ transition ?
+ that.$dialog // wait for modal to slide in
+ .one('bsTransitionEnd', function () {
+ that.$element.trigger('focus').trigger(e)
+ })
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
+ that.$element.trigger('focus').trigger(e)
+ })
+ }
+
+ Modal.prototype.hide = function (e) {
+ if (e) e.preventDefault()
+
+ e = $.Event('hide.bs.modal')
+
+ this.$element.trigger(e)
+
+ if (!this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = false
+
+ this.escape()
+ this.resize()
+
+ $(document).off('focusin.bs.modal')
+
+ this.$element
+ .removeClass('in')
+ .off('click.dismiss.bs.modal')
+ .off('mouseup.dismiss.bs.modal')
+
+ this.$dialog.off('mousedown.dismiss.bs.modal')
+
+ $.support.transition && this.$element.hasClass('fade') ?
+ this.$element
+ .one('bsTransitionEnd', $.proxy(this.hideModal, this))
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
+ this.hideModal()
+ }
+
+ Modal.prototype.enforceFocus = function () {
+ $(document)
+ .off('focusin.bs.modal') // guard against infinite focus loop
+ .on('focusin.bs.modal', $.proxy(function (e) {
+ if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
+ this.$element.trigger('focus')
+ }
+ }, this))
+ }
+
+ Modal.prototype.escape = function () {
+ if (this.isShown && this.options.keyboard) {
+ this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
+ e.which == 27 && this.hide()
+ }, this))
+ } else if (!this.isShown) {
+ this.$element.off('keydown.dismiss.bs.modal')
+ }
+ }
+
+ Modal.prototype.resize = function () {
+ if (this.isShown) {
+ $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
+ } else {
+ $(window).off('resize.bs.modal')
+ }
+ }
+
+ Modal.prototype.hideModal = function () {
+ var that = this
+ this.$element.hide()
+ this.backdrop(function () {
+ that.$body.removeClass('modal-open')
+ that.resetAdjustments()
+ that.resetScrollbar()
+ that.$element.trigger('hidden.bs.modal')
+ })
+ }
+
+ Modal.prototype.removeBackdrop = function () {
+ this.$backdrop && this.$backdrop.remove()
+ this.$backdrop = null
+ }
+
+ Modal.prototype.backdrop = function (callback) {
+ var that = this
+ var animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+ if (this.isShown && this.options.backdrop) {
+ var doAnimate = $.support.transition && animate
+
+ this.$backdrop = $(document.createElement('div'))
+ .addClass('modal-backdrop ' + animate)
+ .appendTo(this.$body)
+
+ this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
+ if (this.ignoreBackdropClick) {
+ this.ignoreBackdropClick = false
+ return
+ }
+ if (e.target !== e.currentTarget) return
+ this.options.backdrop == 'static'
+ ? this.$element[0].focus()
+ : this.hide()
+ }, this))
+
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+ this.$backdrop.addClass('in')
+
+ if (!callback) return
+
+ doAnimate ?
+ this.$backdrop
+ .one('bsTransitionEnd', callback)
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
+ callback()
+
+ } else if (!this.isShown && this.$backdrop) {
+ this.$backdrop.removeClass('in')
+
+ var callbackRemove = function () {
+ that.removeBackdrop()
+ callback && callback()
+ }
+ $.support.transition && this.$element.hasClass('fade') ?
+ this.$backdrop
+ .one('bsTransitionEnd', callbackRemove)
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
+ callbackRemove()
+
+ } else if (callback) {
+ callback()
+ }
+ }
+
+ // these following methods are used to handle overflowing modals
+
+ Modal.prototype.handleUpdate = function () {
+ this.adjustDialog()
+ }
+
+ Modal.prototype.adjustDialog = function () {
+ var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
+
+ this.$element.css({
+ paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
+ paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
+ })
+ }
+
+ Modal.prototype.resetAdjustments = function () {
+ this.$element.css({
+ paddingLeft: '',
+ paddingRight: ''
+ })
+ }
+
+ Modal.prototype.checkScrollbar = function () {
+ var fullWindowWidth = window.innerWidth
+ if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
+ var documentElementRect = document.documentElement.getBoundingClientRect()
+ fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
+ }
+ this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
+ this.scrollbarWidth = this.measureScrollbar()
+ }
+
+ Modal.prototype.setScrollbar = function () {
+ var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
+ this.originalBodyPad = document.body.style.paddingRight || ''
+ if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
+ }
+
+ Modal.prototype.resetScrollbar = function () {
+ this.$body.css('padding-right', this.originalBodyPad)
+ }
+
+ Modal.prototype.measureScrollbar = function () { // thx walsh
+ var scrollDiv = document.createElement('div')
+ scrollDiv.className = 'modal-scrollbar-measure'
+ this.$body.append(scrollDiv)
+ var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
+ this.$body[0].removeChild(scrollDiv)
+ return scrollbarWidth
+ }
+
+
+ // MODAL PLUGIN DEFINITION
+ // =======================
+
+ function Plugin(option, _relatedTarget) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.modal')
+ var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+ if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
+ if (typeof option == 'string') data[option](_relatedTarget)
+ else if (options.show) data.show(_relatedTarget)
+ })
+ }
+
+ var old = $.fn.modal
+
+ $.fn.modal = Plugin
+ $.fn.modal.Constructor = Modal
+
+
+ // MODAL NO CONFLICT
+ // =================
+
+ $.fn.modal.noConflict = function () {
+ $.fn.modal = old
+ return this
+ }
+
+
+ // MODAL DATA-API
+ // ==============
+
+ $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
+ var $this = $(this)
+ var href = $this.attr('href')
+ var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
+ var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
+
+ if ($this.is('a')) e.preventDefault()
+
+ $target.one('show.bs.modal', function (showEvent) {
+ if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
+ $target.one('hidden.bs.modal', function () {
+ $this.is(':visible') && $this.trigger('focus')
+ })
+ })
+ Plugin.call($target, option, this)
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.3.5
+ * http://getbootstrap.com/javascript/#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // TOOLTIP PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Tooltip = function (element, options) {
+ this.type = null
+ this.options = null
+ this.enabled = null
+ this.timeout = null
+ this.hoverState = null
+ this.$element = null
+ this.inState = null
+
+ this.init('tooltip', element, options)
+ }
+
+ Tooltip.VERSION = '3.3.5'
+
+ Tooltip.TRANSITION_DURATION = 150
+
+ Tooltip.DEFAULTS = {
+ animation: true,
+ placement: 'top',
+ selector: false,
+ template: '
',
+ trigger: 'hover focus',
+ title: '',
+ delay: 0,
+ html: false,
+ container: false,
+ viewport: {
+ selector: 'body',
+ padding: 0
+ }
+ }
+
+ Tooltip.prototype.init = function (type, element, options) {
+ this.enabled = true
+ this.type = type
+ this.$element = $(element)
+ this.options = this.getOptions(options)
+ this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
+ this.inState = { click: false, hover: false, focus: false }
+
+ if (this.$element[0] instanceof document.constructor && !this.options.selector) {
+ throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
+ }
+
+ var triggers = this.options.trigger.split(' ')
+
+ for (var i = triggers.length; i--;) {
+ var trigger = triggers[i]
+
+ if (trigger == 'click') {
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+ } else if (trigger != 'manual') {
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+ }
+ }
+
+ this.options.selector ?
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+ this.fixTitle()
+ }
+
+ Tooltip.prototype.getDefaults = function () {
+ return Tooltip.DEFAULTS
+ }
+
+ Tooltip.prototype.getOptions = function (options) {
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+ if (options.delay && typeof options.delay == 'number') {
+ options.delay = {
+ show: options.delay,
+ hide: options.delay
+ }
+ }
+
+ return options
+ }
+
+ Tooltip.prototype.getDelegateOptions = function () {
+ var options = {}
+ var defaults = this.getDefaults()
+
+ this._options && $.each(this._options, function (key, value) {
+ if (defaults[key] != value) options[key] = value
+ })
+
+ return options
+ }
+
+ Tooltip.prototype.enter = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget).data('bs.' + this.type)
+
+ if (!self) {
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+ $(obj.currentTarget).data('bs.' + this.type, self)
+ }
+
+ if (obj instanceof $.Event) {
+ self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
+ }
+
+ if (self.tip().hasClass('in') || self.hoverState == 'in') {
+ self.hoverState = 'in'
+ return
+ }
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'in'
+
+ if (!self.options.delay || !self.options.delay.show) return self.show()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'in') self.show()
+ }, self.options.delay.show)
+ }
+
+ Tooltip.prototype.isInStateTrue = function () {
+ for (var key in this.inState) {
+ if (this.inState[key]) return true
+ }
+
+ return false
+ }
+
+ Tooltip.prototype.leave = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget).data('bs.' + this.type)
+
+ if (!self) {
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+ $(obj.currentTarget).data('bs.' + this.type, self)
+ }
+
+ if (obj instanceof $.Event) {
+ self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
+ }
+
+ if (self.isInStateTrue()) return
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'out'
+
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'out') self.hide()
+ }, self.options.delay.hide)
+ }
+
+ Tooltip.prototype.show = function () {
+ var e = $.Event('show.bs.' + this.type)
+
+ if (this.hasContent() && this.enabled) {
+ this.$element.trigger(e)
+
+ var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
+ if (e.isDefaultPrevented() || !inDom) return
+ var that = this
+
+ var $tip = this.tip()
+
+ var tipId = this.getUID(this.type)
+
+ this.setContent()
+ $tip.attr('id', tipId)
+ this.$element.attr('aria-describedby', tipId)
+
+ if (this.options.animation) $tip.addClass('fade')
+
+ var placement = typeof this.options.placement == 'function' ?
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
+ this.options.placement
+
+ var autoToken = /\s?auto?\s?/i
+ var autoPlace = autoToken.test(placement)
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+ $tip
+ .detach()
+ .css({ top: 0, left: 0, display: 'block' })
+ .addClass(placement)
+ .data('bs.' + this.type, this)
+
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+ this.$element.trigger('inserted.bs.' + this.type)
+
+ var pos = this.getPosition()
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (autoPlace) {
+ var orgPlacement = placement
+ var viewportDim = this.getPosition(this.$viewport)
+
+ placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' :
+ placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' :
+ placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' :
+ placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' :
+ placement
+
+ $tip
+ .removeClass(orgPlacement)
+ .addClass(placement)
+ }
+
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+ this.applyPlacement(calculatedOffset, placement)
+
+ var complete = function () {
+ var prevHoverState = that.hoverState
+ that.$element.trigger('shown.bs.' + that.type)
+ that.hoverState = null
+
+ if (prevHoverState == 'out') that.leave(that)
+ }
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $tip
+ .one('bsTransitionEnd', complete)
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
+ complete()
+ }
+ }
+
+ Tooltip.prototype.applyPlacement = function (offset, placement) {
+ var $tip = this.tip()
+ var width = $tip[0].offsetWidth
+ var height = $tip[0].offsetHeight
+
+ // manually read margins because getBoundingClientRect includes difference
+ var marginTop = parseInt($tip.css('margin-top'), 10)
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+ // we must check for NaN for ie 8/9
+ if (isNaN(marginTop)) marginTop = 0
+ if (isNaN(marginLeft)) marginLeft = 0
+
+ offset.top += marginTop
+ offset.left += marginLeft
+
+ // $.fn.offset doesn't round pixel values
+ // so we use setOffset directly with our own function B-0
+ $.offset.setOffset($tip[0], $.extend({
+ using: function (props) {
+ $tip.css({
+ top: Math.round(props.top),
+ left: Math.round(props.left)
+ })
+ }
+ }, offset), 0)
+
+ $tip.addClass('in')
+
+ // check to see if placing tip in new offset caused the tip to resize itself
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (placement == 'top' && actualHeight != height) {
+ offset.top = offset.top + height - actualHeight
+ }
+
+ var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
+
+ if (delta.left) offset.left += delta.left
+ else offset.top += delta.top
+
+ var isVertical = /top|bottom/.test(placement)
+ var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
+ var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
+
+ $tip.offset(offset)
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
+ }
+
+ Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
+ this.arrow()
+ .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
+ .css(isVertical ? 'top' : 'left', '')
+ }
+
+ Tooltip.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+ $tip.removeClass('fade in top bottom left right')
+ }
+
+ Tooltip.prototype.hide = function (callback) {
+ var that = this
+ var $tip = $(this.$tip)
+ var e = $.Event('hide.bs.' + this.type)
+
+ function complete() {
+ if (that.hoverState != 'in') $tip.detach()
+ that.$element
+ .removeAttr('aria-describedby')
+ .trigger('hidden.bs.' + that.type)
+ callback && callback()
+ }
+
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ $tip.removeClass('in')
+
+ $.support.transition && $tip.hasClass('fade') ?
+ $tip
+ .one('bsTransitionEnd', complete)
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
+ complete()
+
+ this.hoverState = null
+
+ return this
+ }
+
+ Tooltip.prototype.fixTitle = function () {
+ var $e = this.$element
+ if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+ }
+ }
+
+ Tooltip.prototype.hasContent = function () {
+ return this.getTitle()
+ }
+
+ Tooltip.prototype.getPosition = function ($element) {
+ $element = $element || this.$element
+
+ var el = $element[0]
+ var isBody = el.tagName == 'BODY'
+
+ var elRect = el.getBoundingClientRect()
+ if (elRect.width == null) {
+ // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
+ elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
+ }
+ var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
+ var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
+ var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
+
+ return $.extend({}, elRect, scroll, outerDims, elOffset)
+ }
+
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
+
+ }
+
+ Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
+ var delta = { top: 0, left: 0 }
+ if (!this.$viewport) return delta
+
+ var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
+ var viewportDimensions = this.getPosition(this.$viewport)
+
+ if (/right|left/.test(placement)) {
+ var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
+ var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
+ if (topEdgeOffset < viewportDimensions.top) { // top overflow
+ delta.top = viewportDimensions.top - topEdgeOffset
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
+ }
+ } else {
+ var leftEdgeOffset = pos.left - viewportPadding
+ var rightEdgeOffset = pos.left + viewportPadding + actualWidth
+ if (leftEdgeOffset < viewportDimensions.left) { // left overflow
+ delta.left = viewportDimensions.left - leftEdgeOffset
+ } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
+ }
+ }
+
+ return delta
+ }
+
+ Tooltip.prototype.getTitle = function () {
+ var title
+ var $e = this.$element
+ var o = this.options
+
+ title = $e.attr('data-original-title')
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
+
+ return title
+ }
+
+ Tooltip.prototype.getUID = function (prefix) {
+ do prefix += ~~(Math.random() * 1000000)
+ while (document.getElementById(prefix))
+ return prefix
+ }
+
+ Tooltip.prototype.tip = function () {
+ if (!this.$tip) {
+ this.$tip = $(this.options.template)
+ if (this.$tip.length != 1) {
+ throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
+ }
+ }
+ return this.$tip
+ }
+
+ Tooltip.prototype.arrow = function () {
+ return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
+ }
+
+ Tooltip.prototype.enable = function () {
+ this.enabled = true
+ }
+
+ Tooltip.prototype.disable = function () {
+ this.enabled = false
+ }
+
+ Tooltip.prototype.toggleEnabled = function () {
+ this.enabled = !this.enabled
+ }
+
+ Tooltip.prototype.toggle = function (e) {
+ var self = this
+ if (e) {
+ self = $(e.currentTarget).data('bs.' + this.type)
+ if (!self) {
+ self = new this.constructor(e.currentTarget, this.getDelegateOptions())
+ $(e.currentTarget).data('bs.' + this.type, self)
+ }
+ }
+
+ if (e) {
+ self.inState.click = !self.inState.click
+ if (self.isInStateTrue()) self.enter(self)
+ else self.leave(self)
+ } else {
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+ }
+ }
+
+ Tooltip.prototype.destroy = function () {
+ var that = this
+ clearTimeout(this.timeout)
+ this.hide(function () {
+ that.$element.off('.' + that.type).removeData('bs.' + that.type)
+ if (that.$tip) {
+ that.$tip.detach()
+ }
+ that.$tip = null
+ that.$arrow = null
+ that.$viewport = null
+ })
+ }
+
+
+ // TOOLTIP PLUGIN DEFINITION
+ // =========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tooltip')
+ var options = typeof option == 'object' && option
+
+ if (!data && /destroy|hide/.test(option)) return
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.tooltip
+
+ $.fn.tooltip = Plugin
+ $.fn.tooltip.Constructor = Tooltip
+
+
+ // TOOLTIP NO CONFLICT
+ // ===================
+
+ $.fn.tooltip.noConflict = function () {
+ $.fn.tooltip = old
+ return this
+ }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: popover.js v3.3.5
+ * http://getbootstrap.com/javascript/#popovers
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // POPOVER PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Popover = function (element, options) {
+ this.init('popover', element, options)
+ }
+
+ if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+ Popover.VERSION = '3.3.5'
+
+ Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
+ placement: 'right',
+ trigger: 'click',
+ content: '',
+ template: '
'
+ })
+
+
+ // NOTE: POPOVER EXTENDS tooltip.js
+ // ================================
+
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+ Popover.prototype.constructor = Popover
+
+ Popover.prototype.getDefaults = function () {
+ return Popover.DEFAULTS
+ }
+
+ Popover.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+ var content = this.getContent()
+
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+ $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
+ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+ ](content)
+
+ $tip.removeClass('fade top bottom left right in')
+
+ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+ // this manually by checking the contents.
+ if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+ }
+
+ Popover.prototype.hasContent = function () {
+ return this.getTitle() || this.getContent()
+ }
+
+ Popover.prototype.getContent = function () {
+ var $e = this.$element
+ var o = this.options
+
+ return $e.attr('data-content')
+ || (typeof o.content == 'function' ?
+ o.content.call($e[0]) :
+ o.content)
+ }
+
+ Popover.prototype.arrow = function () {
+ return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
+ }
+
+
+ // POPOVER PLUGIN DEFINITION
+ // =========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.popover')
+ var options = typeof option == 'object' && option
+
+ if (!data && /destroy|hide/.test(option)) return
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.popover
+
+ $.fn.popover = Plugin
+ $.fn.popover.Constructor = Popover
+
+
+ // POPOVER NO CONFLICT
+ // ===================
+
+ $.fn.popover.noConflict = function () {
+ $.fn.popover = old
+ return this
+ }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: scrollspy.js v3.3.5
+ * http://getbootstrap.com/javascript/#scrollspy
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // SCROLLSPY CLASS DEFINITION
+ // ==========================
+
+ function ScrollSpy(element, options) {
+ this.$body = $(document.body)
+ this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
+ this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
+ this.selector = (this.options.target || '') + ' .nav li > a'
+ this.offsets = []
+ this.targets = []
+ this.activeTarget = null
+ this.scrollHeight = 0
+
+ this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
+ this.refresh()
+ this.process()
+ }
+
+ ScrollSpy.VERSION = '3.3.5'
+
+ ScrollSpy.DEFAULTS = {
+ offset: 10
+ }
+
+ ScrollSpy.prototype.getScrollHeight = function () {
+ return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
+ }
+
+ ScrollSpy.prototype.refresh = function () {
+ var that = this
+ var offsetMethod = 'offset'
+ var offsetBase = 0
+
+ this.offsets = []
+ this.targets = []
+ this.scrollHeight = this.getScrollHeight()
+
+ if (!$.isWindow(this.$scrollElement[0])) {
+ offsetMethod = 'position'
+ offsetBase = this.$scrollElement.scrollTop()
+ }
+
+ this.$body
+ .find(this.selector)
+ .map(function () {
+ var $el = $(this)
+ var href = $el.data('target') || $el.attr('href')
+ var $href = /^#./.test(href) && $(href)
+
+ return ($href
+ && $href.length
+ && $href.is(':visible')
+ && [[$href[offsetMethod]().top + offsetBase, href]]) || null
+ })
+ .sort(function (a, b) { return a[0] - b[0] })
+ .each(function () {
+ that.offsets.push(this[0])
+ that.targets.push(this[1])
+ })
+ }
+
+ ScrollSpy.prototype.process = function () {
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
+ var scrollHeight = this.getScrollHeight()
+ var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
+ var offsets = this.offsets
+ var targets = this.targets
+ var activeTarget = this.activeTarget
+ var i
+
+ if (this.scrollHeight != scrollHeight) {
+ this.refresh()
+ }
+
+ if (scrollTop >= maxScroll) {
+ return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
+ }
+
+ if (activeTarget && scrollTop < offsets[0]) {
+ this.activeTarget = null
+ return this.clear()
+ }
+
+ for (i = offsets.length; i--;) {
+ activeTarget != targets[i]
+ && scrollTop >= offsets[i]
+ && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
+ && this.activate(targets[i])
+ }
+ }
+
+ ScrollSpy.prototype.activate = function (target) {
+ this.activeTarget = target
+
+ this.clear()
+
+ var selector = this.selector +
+ '[data-target="' + target + '"],' +
+ this.selector + '[href="' + target + '"]'
+
+ var active = $(selector)
+ .parents('li')
+ .addClass('active')
+
+ if (active.parent('.dropdown-menu').length) {
+ active = active
+ .closest('li.dropdown')
+ .addClass('active')
+ }
+
+ active.trigger('activate.bs.scrollspy')
+ }
+
+ ScrollSpy.prototype.clear = function () {
+ $(this.selector)
+ .parentsUntil(this.options.target, '.active')
+ .removeClass('active')
+ }
+
+
+ // SCROLLSPY PLUGIN DEFINITION
+ // ===========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.scrollspy')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.scrollspy
+
+ $.fn.scrollspy = Plugin
+ $.fn.scrollspy.Constructor = ScrollSpy
+
+
+ // SCROLLSPY NO CONFLICT
+ // =====================
+
+ $.fn.scrollspy.noConflict = function () {
+ $.fn.scrollspy = old
+ return this
+ }
+
+
+ // SCROLLSPY DATA-API
+ // ==================
+
+ $(window).on('load.bs.scrollspy.data-api', function () {
+ $('[data-spy="scroll"]').each(function () {
+ var $spy = $(this)
+ Plugin.call($spy, $spy.data())
+ })
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tab.js v3.3.5
+ * http://getbootstrap.com/javascript/#tabs
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // TAB CLASS DEFINITION
+ // ====================
+
+ var Tab = function (element) {
+ // jscs:disable requireDollarBeforejQueryAssignment
+ this.element = $(element)
+ // jscs:enable requireDollarBeforejQueryAssignment
+ }
+
+ Tab.VERSION = '3.3.5'
+
+ Tab.TRANSITION_DURATION = 150
+
+ Tab.prototype.show = function () {
+ var $this = this.element
+ var $ul = $this.closest('ul:not(.dropdown-menu)')
+ var selector = $this.data('target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ }
+
+ if ($this.parent('li').hasClass('active')) return
+
+ var $previous = $ul.find('.active:last a')
+ var hideEvent = $.Event('hide.bs.tab', {
+ relatedTarget: $this[0]
+ })
+ var showEvent = $.Event('show.bs.tab', {
+ relatedTarget: $previous[0]
+ })
+
+ $previous.trigger(hideEvent)
+ $this.trigger(showEvent)
+
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
+
+ var $target = $(selector)
+
+ this.activate($this.closest('li'), $ul)
+ this.activate($target, $target.parent(), function () {
+ $previous.trigger({
+ type: 'hidden.bs.tab',
+ relatedTarget: $this[0]
+ })
+ $this.trigger({
+ type: 'shown.bs.tab',
+ relatedTarget: $previous[0]
+ })
+ })
+ }
+
+ Tab.prototype.activate = function (element, container, callback) {
+ var $active = container.find('> .active')
+ var transition = callback
+ && $.support.transition
+ && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
+
+ function next() {
+ $active
+ .removeClass('active')
+ .find('> .dropdown-menu > .active')
+ .removeClass('active')
+ .end()
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', false)
+
+ element
+ .addClass('active')
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', true)
+
+ if (transition) {
+ element[0].offsetWidth // reflow for transition
+ element.addClass('in')
+ } else {
+ element.removeClass('fade')
+ }
+
+ if (element.parent('.dropdown-menu').length) {
+ element
+ .closest('li.dropdown')
+ .addClass('active')
+ .end()
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', true)
+ }
+
+ callback && callback()
+ }
+
+ $active.length && transition ?
+ $active
+ .one('bsTransitionEnd', next)
+ .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
+ next()
+
+ $active.removeClass('in')
+ }
+
+
+ // TAB PLUGIN DEFINITION
+ // =====================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tab')
+
+ if (!data) $this.data('bs.tab', (data = new Tab(this)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.tab
+
+ $.fn.tab = Plugin
+ $.fn.tab.Constructor = Tab
+
+
+ // TAB NO CONFLICT
+ // ===============
+
+ $.fn.tab.noConflict = function () {
+ $.fn.tab = old
+ return this
+ }
+
+
+ // TAB DATA-API
+ // ============
+
+ var clickHandler = function (e) {
+ e.preventDefault()
+ Plugin.call($(this), 'show')
+ }
+
+ $(document)
+ .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
+ .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: affix.js v3.3.5
+ * http://getbootstrap.com/javascript/#affix
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // AFFIX CLASS DEFINITION
+ // ======================
+
+ var Affix = function (element, options) {
+ this.options = $.extend({}, Affix.DEFAULTS, options)
+
+ this.$target = $(this.options.target)
+ .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
+ .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
+
+ this.$element = $(element)
+ this.affixed = null
+ this.unpin = null
+ this.pinnedOffset = null
+
+ this.checkPosition()
+ }
+
+ Affix.VERSION = '3.3.5'
+
+ Affix.RESET = 'affix affix-top affix-bottom'
+
+ Affix.DEFAULTS = {
+ offset: 0,
+ target: window
+ }
+
+ Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
+ var scrollTop = this.$target.scrollTop()
+ var position = this.$element.offset()
+ var targetHeight = this.$target.height()
+
+ if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
+
+ if (this.affixed == 'bottom') {
+ if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
+ return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
+ }
+
+ var initializing = this.affixed == null
+ var colliderTop = initializing ? scrollTop : position.top
+ var colliderHeight = initializing ? targetHeight : height
+
+ if (offsetTop != null && scrollTop <= offsetTop) return 'top'
+ if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
+
+ return false
+ }
+
+ Affix.prototype.getPinnedOffset = function () {
+ if (this.pinnedOffset) return this.pinnedOffset
+ this.$element.removeClass(Affix.RESET).addClass('affix')
+ var scrollTop = this.$target.scrollTop()
+ var position = this.$element.offset()
+ return (this.pinnedOffset = position.top - scrollTop)
+ }
+
+ Affix.prototype.checkPositionWithEventLoop = function () {
+ setTimeout($.proxy(this.checkPosition, this), 1)
+ }
+
+ Affix.prototype.checkPosition = function () {
+ if (!this.$element.is(':visible')) return
+
+ var height = this.$element.height()
+ var offset = this.options.offset
+ var offsetTop = offset.top
+ var offsetBottom = offset.bottom
+ var scrollHeight = Math.max($(document).height(), $(document.body).height())
+
+ if (typeof offset != 'object') offsetBottom = offsetTop = offset
+ if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
+ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
+
+ var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
+
+ if (this.affixed != affix) {
+ if (this.unpin != null) this.$element.css('top', '')
+
+ var affixType = 'affix' + (affix ? '-' + affix : '')
+ var e = $.Event(affixType + '.bs.affix')
+
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ this.affixed = affix
+ this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
+
+ this.$element
+ .removeClass(Affix.RESET)
+ .addClass(affixType)
+ .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
+ }
+
+ if (affix == 'bottom') {
+ this.$element.offset({
+ top: scrollHeight - height - offsetBottom
+ })
+ }
+ }
+
+
+ // AFFIX PLUGIN DEFINITION
+ // =======================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.affix')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.affix
+
+ $.fn.affix = Plugin
+ $.fn.affix.Constructor = Affix
+
+
+ // AFFIX NO CONFLICT
+ // =================
+
+ $.fn.affix.noConflict = function () {
+ $.fn.affix = old
+ return this
+ }
+
+
+ // AFFIX DATA-API
+ // ==============
+
+ $(window).on('load', function () {
+ $('[data-spy="affix"]').each(function () {
+ var $spy = $(this)
+ var data = $spy.data()
+
+ data.offset = data.offset || {}
+
+ if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
+ if (data.offsetTop != null) data.offset.top = data.offsetTop
+
+ Plugin.call($spy, data)
+ })
+ })
+
+}(jQuery);
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/js/bootstrap.min.js b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/js/bootstrap.min.js
new file mode 100644
index 00000000..133aeecb
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/js/bootstrap.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under the MIT license
+ */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.5",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.5",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.5",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.5",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.5",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&j
document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.5",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.5",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.5",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
\ No newline at end of file
diff --git a/Istio-Samples/bookinfo/src/productpage/static/bootstrap/js/npm.js b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/js/npm.js
new file mode 100644
index 00000000..bf6aa806
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/static/bootstrap/js/npm.js
@@ -0,0 +1,13 @@
+// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
+require('../../js/transition.js')
+require('../../js/alert.js')
+require('../../js/button.js')
+require('../../js/carousel.js')
+require('../../js/collapse.js')
+require('../../js/dropdown.js')
+require('../../js/modal.js')
+require('../../js/tooltip.js')
+require('../../js/popover.js')
+require('../../js/scrollspy.js')
+require('../../js/tab.js')
+require('../../js/affix.js')
\ No newline at end of file
diff --git a/Istio-Samples/bookinfo/src/productpage/static/jquery.min.js b/Istio-Samples/bookinfo/src/productpage/static/jquery.min.js
new file mode 100644
index 00000000..47b63970
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/static/jquery.min.js
@@ -0,0 +1,2 @@
+/*! jQuery v3.5.0 | (c) JS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML=" ",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML=" ";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML=" ",y.option=!!ce.lastChild;var ge={thead:[1,""],col:[2,""],tr:[2,""],td:[3,""],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n"," "]);var me=/<|?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0
+
+
+{% endblock %}
+
+{% block styles %}
+
+
+
+
+
+{% endblock %}
+{% block scripts %}
+
+
+
+
+
+{% endblock %}
+{% block title %}Simple Bookstore App{% endblock %}
+{% block content %}
+
+
Hello! This is a simple bookstore application consisting of three services as shown below
+
+{% autoescape false %}
+{{ serviceTable }}
+{% endautoescape %}
+
+
Click on one of the links below to auto generate a request to the backend as a real user or a tester
+
+
+Normal user
+Test user
+{% endblock %}
\ No newline at end of file
diff --git a/Istio-Samples/bookinfo/src/productpage/templates/productpage.html b/Istio-Samples/bookinfo/src/productpage/templates/productpage.html
new file mode 100644
index 00000000..0f20ecbe
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/templates/productpage.html
@@ -0,0 +1,166 @@
+{% extends "bootstrap/base.html" %}
+{% block metas %}
+
+
+
+{% endblock %}
+
+{% block styles %}
+
+
+
+
+
+{% endblock %}
+{% block scripts %}
+
+
+
+
+
+
+
+{% endblock %}
+{% block title %}Simple Bookstore App{% endblock %}
+{% block content %}
+
+
+
+
+ {% if user: %}
+
+
+ {{ user }} ( sign out )
+
+ {% else %}
+
Sign
+ in
+ {% endif %}
+
+
+
+
+
+
+
+
+
+
+
{{ product.title }}
+ {% autoescape false %}
+
Summary: {{ product.descriptionHtml }}
+ {% endautoescape %}
+
+
+
+
+
+ {% if detailsStatus == 200: %}
+
Book Details
+
+ Type: {{ details.type }}
+ Pages: {{ details.pages }}
+ Publisher: {{ details.publisher }}
+ Language: {{ details.language }}
+ ISBN-10: {{ details['ISBN-10'] }}
+ ISBN-13: {{ details['ISBN-13'] }}
+
+ {% else %}
+
Error fetching product details!
+ {% if details: %}
+
{{ details.error }}
+ {% endif %}
+ {% endif %}
+
+
+
+ {% if reviewsStatus == 200: %}
+
Book Reviews
+ {% for review in reviews.reviews %}
+
+ {{ review.text }}
+ {{ review.reviewer }}
+ {% if review.rating: %}
+ {% if review.rating.stars: %}
+
+
+ {% for n in range(review.rating.stars) %}
+
+ {% endfor %}
+
+ {% for n in range(5 - review.rating.stars) %}
+
+ {% endfor %}
+
+ {% elif review.rating.error: %}
+ {{ review.rating.error }}
+ {% endif %}
+ {% endif %}
+
+ {% endfor %}
+
+ Reviews served by:
+ {{ reviews.podname }}
+ {% if reviews.clustername != "null" %}
+ on cluster {{ reviews.clustername }}
+ {% endif %}
+
+ {% else %}
+
Error fetching product reviews!
+ {% if reviews: %}
+
{{ reviews.error }}
+ {% endif %}
+ {% endif %}
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/Istio-Samples/bookinfo/src/productpage/test-requirements.txt b/Istio-Samples/bookinfo/src/productpage/test-requirements.txt
new file mode 100644
index 00000000..f756640f
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/test-requirements.txt
@@ -0,0 +1 @@
+requests-mock==1.5.2
diff --git a/Istio-Samples/bookinfo/src/productpage/tests/unit/test_productpage.py b/Istio-Samples/bookinfo/src/productpage/tests/unit/test_productpage.py
new file mode 100644
index 00000000..58e54945
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/productpage/tests/unit/test_productpage.py
@@ -0,0 +1,87 @@
+#
+# Copyright 2018 Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Run from the top level productpage directory with:
+#
+# pip install -r test-requirements.txt
+# python -m unittest discover tests/unit
+
+import unittest
+
+import requests_mock
+
+import productpage
+
+
+class ApplianceTest(unittest.TestCase):
+
+ def setUp(self):
+ self.app = productpage.app.test_client()
+
+ @requests_mock.Mocker()
+ def test_header_propagation_reviews(self, m):
+ """ Check that tracing headers are forwarded correctly """
+ product_id = 0
+ # Register expected headers with the mock. If the headers
+ # don't match, the mock won't fire, an E500 will be triggered
+ # and the test will fail.
+ expected_headers = {
+ 'x-request-id': '34eeb41d-d267-9e49-8b84-dde403fc5b72',
+ 'x-b3-traceid': '40c7fdf104e3de67',
+ 'x-b3-spanid': '40c7fdf104e3de67',
+ 'x-b3-sampled': '1',
+ 'sw8': '40c7fdf104e3de67'
+ }
+ m.get("http://reviews:9080/reviews/%d" % product_id, text='{}',
+ request_headers=expected_headers)
+
+ uri = "/api/v1/products/%d/reviews" % product_id
+ headers = {
+ 'x-request-id': '34eeb41d-d267-9e49-8b84-dde403fc5b72',
+ 'x-b3-traceid': '40c7fdf104e3de67',
+ 'x-b3-spanid': '40c7fdf104e3de67',
+ 'x-b3-sampled': '1',
+ 'sw8': '40c7fdf104e3de67'
+ }
+ actual = self.app.get(uri, headers=headers)
+ self.assertEqual(200, actual.status_code)
+
+ @requests_mock.Mocker()
+ def test_header_propagation_ratings(self, m):
+ """ Check that tracing headers are forwarded correctly """
+ product_id = 0
+ # Register expected headers with the mock. If the headers
+ # don't match, the mock won't fire, an E500 will be triggered
+ # and the test will fail.
+ expected_headers = {
+ 'x-request-id': '34eeb41d-d267-9e49-8b84-dde403fc5b73',
+ 'x-b3-traceid': '30c7fdf104e3de66',
+ 'x-b3-spanid': '30c7fdf104e3de66',
+ 'x-b3-sampled': '1',
+ 'sw8': '40c7fdf104e3de67'
+ }
+ m.get("http://ratings:9080/ratings/%d" % product_id, text='{}',
+ request_headers=expected_headers)
+
+ uri = "/api/v1/products/%d/ratings" % product_id
+ headers = {
+ 'x-request-id': '34eeb41d-d267-9e49-8b84-dde403fc5b73',
+ 'x-b3-traceid': '30c7fdf104e3de66',
+ 'x-b3-spanid': '30c7fdf104e3de66',
+ 'x-b3-sampled': '1',
+ 'sw8': '40c7fdf104e3de67'
+ }
+ actual = self.app.get(uri, headers=headers)
+ self.assertEqual(200, actual.status_code)
diff --git a/Istio-Samples/bookinfo/src/ratings/Dockerfile b/Istio-Samples/bookinfo/src/ratings/Dockerfile
new file mode 100644
index 00000000..87e77347
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/ratings/Dockerfile
@@ -0,0 +1,33 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM node:18.16-slim
+
+#hadolint ignore=DL3008
+RUN apt-get update \
+ && apt-get install curl --no-install-recommends -y \
+ && rm -rf /var/lib/apt/lists/*
+
+ARG service_version
+ENV SERVICE_VERSION ${service_version:-v1}
+
+COPY package.json /opt/microservices/
+COPY ratings.js /opt/microservices/
+WORKDIR /opt/microservices
+RUN npm install
+
+EXPOSE 9080
+CMD ["node", "/opt/microservices/ratings.js", "9080"]
+
+USER 1000
diff --git a/Istio-Samples/bookinfo/src/ratings/package.json b/Istio-Samples/bookinfo/src/ratings/package.json
new file mode 100644
index 00000000..f0498224
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/ratings/package.json
@@ -0,0 +1,11 @@
+{
+ "scripts": {
+ "start": "node ratings.js"
+ },
+ "dependencies": {
+ "httpdispatcher": "1.0.0",
+ "mongodb": "^3.6.0",
+ "mysql": "^2.15.0"
+ },
+ "private": true
+}
diff --git a/Istio-Samples/bookinfo/src/ratings/ratings.js b/Istio-Samples/bookinfo/src/ratings/ratings.js
new file mode 100644
index 00000000..63447686
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/ratings/ratings.js
@@ -0,0 +1,272 @@
+// Copyright Istio Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+var http = require('http')
+var dispatcher = require('httpdispatcher')
+
+var port = parseInt(process.argv[2])
+
+var userAddedRatings = [] // used to demonstrate POST functionality
+
+var unavailable = false
+var healthy = true
+
+if (process.env.SERVICE_VERSION === 'v-unavailable') {
+ // make the service unavailable once in 60 seconds
+ setInterval(function () {
+ unavailable = !unavailable
+ }, 60000);
+}
+
+if (process.env.SERVICE_VERSION === 'v-unhealthy') {
+ // make the service unavailable once in 15 minutes for 15 minutes.
+ // 15 minutes is chosen since the Kubernetes's exponential back-off is reset after 10 minutes
+ // of successful execution
+ // see https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy
+ // Kiali shows the last 10 or 30 minutes, so to show the error rate of 50%,
+ // it will be required to run the service for 30 minutes, 15 minutes of each state (healthy/unhealthy)
+ setInterval(function () {
+ healthy = !healthy
+ unavailable = !unavailable
+ }, 900000);
+}
+
+/**
+ * We default to using mongodb, if DB_TYPE is not set to mysql.
+ */
+if (process.env.SERVICE_VERSION === 'v2') {
+ if (process.env.DB_TYPE === 'mysql') {
+ var mysql = require('mysql')
+ var hostName = process.env.MYSQL_DB_HOST
+ var portNumber = process.env.MYSQL_DB_PORT
+ var username = process.env.MYSQL_DB_USER
+ var password = process.env.MYSQL_DB_PASSWORD
+ } else {
+ var MongoClient = require('mongodb').MongoClient
+ var url = process.env.MONGO_DB_URL
+ }
+}
+
+dispatcher.onPost(/^\/ratings\/[0-9]*/, function (req, res) {
+ var productIdStr = req.url.split('/').pop()
+ var productId = parseInt(productIdStr)
+ var ratings = {}
+
+ if (Number.isNaN(productId)) {
+ res.writeHead(400, {'Content-type': 'application/json'})
+ res.end(JSON.stringify({error: 'please provide numeric product ID'}))
+ return
+ }
+
+ try {
+ ratings = JSON.parse(req.body)
+ } catch (error) {
+ res.writeHead(400, {'Content-type': 'application/json'})
+ res.end(JSON.stringify({error: 'please provide valid ratings JSON'}))
+ return
+ }
+
+ if (process.env.SERVICE_VERSION === 'v2') { // the version that is backed by a database
+ res.writeHead(501, {'Content-type': 'application/json'})
+ res.end(JSON.stringify({error: 'Post not implemented for database backed ratings'}))
+ } else { // the version that holds ratings in-memory
+ res.writeHead(200, {'Content-type': 'application/json'})
+ res.end(JSON.stringify(putLocalReviews(productId, ratings)))
+ }
+})
+
+dispatcher.onGet(/^\/ratings\/[0-9]*/, function (req, res) {
+ var productIdStr = req.url.split('/').pop()
+ var productId = parseInt(productIdStr)
+
+ if (Number.isNaN(productId)) {
+ res.writeHead(400, {'Content-type': 'application/json'})
+ res.end(JSON.stringify({error: 'please provide numeric product ID'}))
+ } else if (process.env.SERVICE_VERSION === 'v2') {
+ var firstRating = 0
+ var secondRating = 0
+
+ if (process.env.DB_TYPE === 'mysql') {
+ var connection = mysql.createConnection({
+ host: hostName,
+ port: portNumber,
+ user: username,
+ password: password,
+ database: 'test'
+ })
+
+ connection.connect(function(err) {
+ if (err) {
+ res.end(JSON.stringify({error: 'could not connect to ratings database'}))
+ console.log(err)
+ return
+ }
+ connection.query('SELECT Rating FROM ratings', function (err, results, fields) {
+ if (err) {
+ res.writeHead(500, {'Content-type': 'application/json'})
+ res.end(JSON.stringify({error: 'could not perform select'}))
+ console.log(err)
+ } else {
+ if (results[0]) {
+ firstRating = results[0].Rating
+ }
+ if (results[1]) {
+ secondRating = results[1].Rating
+ }
+ var result = {
+ id: productId,
+ ratings: {
+ Reviewer1: firstRating,
+ Reviewer2: secondRating
+ }
+ }
+ res.writeHead(200, {'Content-type': 'application/json'})
+ res.end(JSON.stringify(result))
+ }
+ })
+ // close the connection
+ connection.end()
+ })
+ } else {
+ MongoClient.connect(url, function (err, client) {
+ if (err) {
+ res.writeHead(500, {'Content-type': 'application/json'})
+ res.end(JSON.stringify({error: 'could not connect to ratings database'}))
+ console.log(err)
+ } else {
+ const db = client.db("test")
+ db.collection('ratings').find({}).toArray(function (err, data) {
+ if (err) {
+ res.writeHead(500, {'Content-type': 'application/json'})
+ res.end(JSON.stringify({error: 'could not load ratings from database'}))
+ console.log(err)
+ } else {
+ if (data[0]) {
+ firstRating = data[0].rating
+ }
+ if (data[1]) {
+ secondRating = data[1].rating
+ }
+ var result = {
+ id: productId,
+ ratings: {
+ Reviewer1: firstRating,
+ Reviewer2: secondRating
+ }
+ }
+ res.writeHead(200, {'Content-type': 'application/json'})
+ res.end(JSON.stringify(result))
+ }
+ // close client once done:
+ client.close()
+ })
+ }
+ })
+ }
+ } else {
+ if (process.env.SERVICE_VERSION === 'v-faulty') {
+ // in half of the cases return error,
+ // in another half proceed as usual
+ var random = Math.random(); // returns [0,1]
+ if (random <= 0.5) {
+ getLocalReviewsServiceUnavailable(res)
+ } else {
+ getLocalReviewsSuccessful(res, productId)
+ }
+ }
+ else if (process.env.SERVICE_VERSION === 'v-delayed') {
+ // in half of the cases delay for 7 seconds,
+ // in another half proceed as usual
+ var random = Math.random(); // returns [0,1]
+ if (random <= 0.5) {
+ setTimeout(getLocalReviewsSuccessful, 7000, res, productId)
+ } else {
+ getLocalReviewsSuccessful(res, productId)
+ }
+ }
+ else if (process.env.SERVICE_VERSION === 'v-unavailable' || process.env.SERVICE_VERSION === 'v-unhealthy') {
+ if (unavailable) {
+ getLocalReviewsServiceUnavailable(res)
+ } else {
+ getLocalReviewsSuccessful(res, productId)
+ }
+ }
+ else {
+ getLocalReviewsSuccessful(res, productId)
+ }
+ }
+})
+
+dispatcher.onGet('/health', function (req, res) {
+ if (healthy) {
+ res.writeHead(200, {'Content-type': 'application/json'})
+ res.end(JSON.stringify({status: 'Ratings is healthy'}))
+ } else {
+ res.writeHead(500, {'Content-type': 'application/json'})
+ res.end(JSON.stringify({status: 'Ratings is not healthy'}))
+ }
+})
+
+function putLocalReviews (productId, ratings) {
+ userAddedRatings[productId] = {
+ id: productId,
+ ratings: ratings
+ }
+ return getLocalReviews(productId)
+}
+
+function getLocalReviewsSuccessful(res, productId) {
+ res.writeHead(200, {'Content-type': 'application/json'})
+ res.end(JSON.stringify(getLocalReviews(productId)))
+}
+
+function getLocalReviewsServiceUnavailable(res) {
+ res.writeHead(503, {'Content-type': 'application/json'})
+ res.end(JSON.stringify({error: 'Service unavailable'}))
+}
+
+function getLocalReviews (productId) {
+ if (typeof userAddedRatings[productId] !== 'undefined') {
+ return userAddedRatings[productId]
+ }
+ return {
+ id: productId,
+ ratings: {
+ 'Reviewer1': 5,
+ 'Reviewer2': 4
+ }
+ }
+}
+
+function handleRequest (request, response) {
+ try {
+ console.log(request.method + ' ' + request.url)
+ dispatcher.dispatch(request, response)
+ } catch (err) {
+ console.log(err)
+ }
+}
+
+var server = http.createServer(handleRequest)
+
+process.on('SIGTERM', function () {
+ console.log("SIGTERM received")
+ server.close(function () {
+ process.exit(0);
+ });
+});
+
+server.listen(port, function () {
+ console.log('Server listening on: http://0.0.0.0:%s', port)
+})
diff --git a/Istio-Samples/bookinfo/src/reviews/.gitignore b/Istio-Samples/bookinfo/src/reviews/.gitignore
new file mode 100644
index 00000000..2dcaf499
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/.gitignore
@@ -0,0 +1,3 @@
+.gradle
+reviews-application/build/
+reviews-wlpcfg/servers/LibertyProjectServer/apps/
diff --git a/Istio-Samples/bookinfo/src/reviews/Dockerfile b/Istio-Samples/bookinfo/src/reviews/Dockerfile
new file mode 100644
index 00000000..8896dab1
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/Dockerfile
@@ -0,0 +1,42 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM gradle:4.8.1 as builder
+
+# Not sure why but we need root to build. Ignore lint error, this is for a multistage builder so it doesn't matter.
+# hadolint ignore=DL3002
+USER 0
+COPY . /home/gradle
+
+RUN gradle build
+
+# Use library image once https://github.com/OpenLiberty/ci.docker/issues/241
+# is fixed
+FROM gcr.io/istio-testing/websphere-liberty:22.0.0.8-full-java8-ibmjava
+
+ENV SERVERDIRNAME reviews
+
+COPY --from=builder /home/gradle/reviews-wlpcfg/servers/LibertyProjectServer/ /opt/ol/wlp/usr/servers/defaultServer/
+
+RUN /opt/ol/wlp/bin/featureUtility installServerFeatures --acceptLicense /opt/ol/wlp/usr/servers/defaultServer/server.xml && \
+ chmod -R g=rwx /opt/ol/wlp/output/defaultServer/
+
+ARG service_version
+ARG enable_ratings
+ARG star_color
+ENV SERVICE_VERSION ${service_version:-v1}
+ENV ENABLE_RATINGS ${enable_ratings:-false}
+ENV STAR_COLOR ${star_color:-black}
+
+CMD ["/opt/ol/wlp/bin/server", "run", "defaultServer"]
diff --git a/Istio-Samples/bookinfo/src/reviews/build.gradle b/Istio-Samples/bookinfo/src/reviews/build.gradle
new file mode 100644
index 00000000..75bf3608
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/build.gradle
@@ -0,0 +1,7 @@
+allprojects {
+ group = 'org.istio'
+ version = '1.0'
+ repositories {
+ mavenCentral()
+ }
+}
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-application/build.gradle b/Istio-Samples/bookinfo/src/reviews/reviews-application/build.gradle
new file mode 100644
index 00000000..bf0f3752
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/reviews-application/build.gradle
@@ -0,0 +1,19 @@
+apply plugin: 'war'
+
+sourceCompatibility = 1.8
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ providedCompile group:'javax.websocket', name:'javax.websocket-api', version:'1.1'
+ providedCompile group:'javax.ws.rs', name:'javax.ws.rs-api', version:'2.0'
+ providedCompile group:'javax.json', name:'javax.json-api', version:'1.0'
+ providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
+ providedCompile 'javax.annotation:javax.annotation-api:1.2'
+ providedCompile 'javax.inject:javax.inject:1'
+ providedCompile 'javax.enterprise.concurrent:javax.enterprise.concurrent-api:1.0'
+ providedCompile 'javax.enterprise:cdi-api:1.2'
+ providedCompile 'io.swagger:swagger-annotations:1.5.0'
+}
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/java/application/ReviewsApplication.java b/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/java/application/ReviewsApplication.java
new file mode 100644
index 00000000..9f622852
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/java/application/ReviewsApplication.java
@@ -0,0 +1,7 @@
+package application;
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+
+@ApplicationPath("/")
+public class ReviewsApplication extends Application {
+}
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/java/application/rest/LibertyRestEndpoint.java b/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/java/application/rest/LibertyRestEndpoint.java
new file mode 100644
index 00000000..08ca3266
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/java/application/rest/LibertyRestEndpoint.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Istio Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+package application.rest;
+
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.StringReader;
+
+@Path("/")
+public class LibertyRestEndpoint extends Application {
+
+ private final static Boolean ratings_enabled = Boolean.valueOf(System.getenv("ENABLE_RATINGS"));
+ private final static String star_color = System.getenv("STAR_COLOR") == null ? "black" : System.getenv("STAR_COLOR");
+ private final static String services_domain = System.getenv("SERVICES_DOMAIN") == null ? "" : ("." + System.getenv("SERVICES_DOMAIN"));
+ private final static String ratings_hostname = System.getenv("RATINGS_HOSTNAME") == null ? "ratings" : System.getenv("RATINGS_HOSTNAME");
+ private final static String ratings_port = System.getenv("RATINGS_SERVICE_PORT") == null ? "9080" : System.getenv("RATINGS_SERVICE_PORT");
+ private final static String ratings_service = String.format("http://%s%s:%s/ratings", ratings_hostname, services_domain, ratings_port);
+ private final static String pod_hostname = System.getenv("HOSTNAME");
+ private final static String clustername = System.getenv("CLUSTER_NAME");
+ // HTTP headers to propagate for distributed tracing are documented at
+ // https://istio.io/docs/tasks/telemetry/distributed-tracing/overview/#trace-context-propagation
+ private final static String[] headers_to_propagate = {
+ // All applications should propagate x-request-id. This header is
+ // included in access log statements and is used for consistent trace
+ // sampling and log sampling decisions in Istio.
+ "x-request-id",
+
+ // Lightstep tracing header. Propagate this if you use lightstep tracing
+ // in Istio (see
+ // https://istio.io/latest/docs/tasks/observability/distributed-tracing/lightstep/)
+ // Note: this should probably be changed to use B3 or W3C TRACE_CONTEXT.
+ // Lightstep recommends using B3 or TRACE_CONTEXT and most application
+ // libraries from lightstep do not support x-ot-span-context.
+ "x-ot-span-context",
+
+ // Datadog tracing header. Propagate these headers if you use Datadog
+ // tracing.
+ "x-datadog-trace-id",
+ "x-datadog-parent-id",
+ "x-datadog-sampling-priority",
+
+ // W3C Trace Context. Compatible with OpenCensusAgent and Stackdriver Istio
+ // configurations.
+ "traceparent",
+ "tracestate",
+
+ // Cloud trace context. Compatible with OpenCensusAgent and Stackdriver Istio
+ // configurations.
+ "x-cloud-trace-context",
+
+ // Grpc binary trace context. Compatible with OpenCensusAgent nad
+ // Stackdriver Istio configurations.
+ "grpc-trace-bin",
+
+ // b3 trace headers. Compatible with Zipkin, OpenCensusAgent, and
+ // Stackdriver Istio configurations. Commented out since they are
+ // propagated by the OpenTracing tracer above.
+ "x-b3-traceid",
+ "x-b3-spanid",
+ "x-b3-parentspanid",
+ "x-b3-sampled",
+ "x-b3-flags",
+
+ // SkyWalking trace headers.
+ "sw8",
+
+ // Application-specific headers to forward.
+ "end-user",
+ "user-agent",
+
+ // Context and session specific headers
+ "cookie",
+ "authorization",
+ "jwt",
+ };
+
+ private String getJsonResponse(String productId, int starsReviewer1, int starsReviewer2) {
+ String result = "{";
+ result += "\"id\": \"" + productId + "\",";
+ result += "\"podname\": \"" + pod_hostname + "\",";
+ result += "\"clustername\": \"" + clustername + "\",";
+ result += "\"reviews\": [";
+
+ // reviewer 1:
+ result += "{";
+ result += " \"reviewer\": \"Reviewer1\",";
+ result += " \"text\": \"An extremely entertaining play by Shakespeare. The slapstick humour is refreshing!\"";
+ if (ratings_enabled) {
+ if (starsReviewer1 != -1) {
+ result += ", \"rating\": {\"stars\": " + starsReviewer1 + ", \"color\": \"" + star_color + "\"}";
+ }
+ else {
+ result += ", \"rating\": {\"error\": \"Ratings service is currently unavailable\"}";
+ }
+ }
+ result += "},";
+
+ // reviewer 2:
+ result += "{";
+ result += " \"reviewer\": \"Reviewer2\",";
+ result += " \"text\": \"Absolutely fun and entertaining. The play lacks thematic depth when compared to other plays by Shakespeare.\"";
+ if (ratings_enabled) {
+ if (starsReviewer2 != -1) {
+ result += ", \"rating\": {\"stars\": " + starsReviewer2 + ", \"color\": \"" + star_color + "\"}";
+ }
+ else {
+ result += ", \"rating\": {\"error\": \"Ratings service is currently unavailable\"}";
+ }
+ }
+ result += "}";
+
+ result += "]";
+ result += "}";
+
+ return result;
+ }
+
+ private JsonObject getRatings(String productId, HttpHeaders requestHeaders) {
+ ClientBuilder cb = ClientBuilder.newBuilder();
+ Integer timeout = star_color.equals("black") ? 10000 : 2500;
+ cb.property("com.ibm.ws.jaxrs.client.connection.timeout", timeout);
+ cb.property("com.ibm.ws.jaxrs.client.receive.timeout", timeout);
+ Client client = cb.build();
+ WebTarget ratingsTarget = client.target(ratings_service + "/" + productId);
+ Invocation.Builder builder = ratingsTarget.request(MediaType.APPLICATION_JSON);
+ for (String header : headers_to_propagate) {
+ String value = requestHeaders.getHeaderString(header);
+ if (value != null) {
+ builder.header(header,value);
+ }
+ }
+ try {
+ Response r = builder.get();
+
+ int statusCode = r.getStatusInfo().getStatusCode();
+ if (statusCode == Response.Status.OK.getStatusCode()) {
+ try (StringReader stringReader = new StringReader(r.readEntity(String.class));
+ JsonReader jsonReader = Json.createReader(stringReader)) {
+ return jsonReader.readObject();
+ }
+ } else {
+ System.out.println("Error: unable to contact " + ratings_service + " got status of " + statusCode);
+ return null;
+ }
+ } catch (ProcessingException e) {
+ System.err.println("Error: unable to contact " + ratings_service + " got exception " + e);
+ return null;
+ }
+ }
+
+ @GET
+ @Path("/health")
+ public Response health() {
+ return Response.ok().type(MediaType.APPLICATION_JSON).entity("{\"status\": \"Reviews is healthy\"}").build();
+ }
+
+ @GET
+ @Path("/reviews/{productId}")
+ public Response bookReviewsById(@PathParam("productId") int productId, @Context HttpHeaders requestHeaders) {
+ int starsReviewer1 = -1;
+ int starsReviewer2 = -1;
+
+ if (ratings_enabled) {
+ JsonObject ratingsResponse = getRatings(Integer.toString(productId), requestHeaders);
+ if (ratingsResponse != null) {
+ if (ratingsResponse.containsKey("ratings")) {
+ JsonObject ratings = ratingsResponse.getJsonObject("ratings");
+ if (ratings.containsKey("Reviewer1")){
+ starsReviewer1 = ratings.getInt("Reviewer1");
+ }
+ if (ratings.containsKey("Reviewer2")){
+ starsReviewer2 = ratings.getInt("Reviewer2");
+ }
+ }
+ }
+ }
+
+ String jsonResStr = getJsonResponse(Integer.toString(productId), starsReviewer1, starsReviewer2);
+ return Response.ok().type(MediaType.APPLICATION_JSON).entity(jsonResStr).build();
+ }
+}
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/webapp/WEB-INF/ibm-web-ext.xml b/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/webapp/WEB-INF/ibm-web-ext.xml
new file mode 100644
index 00000000..68c52176
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/webapp/WEB-INF/ibm-web-ext.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/webapp/WEB-INF/web.xml b/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000..a3823f10
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,10 @@
+
+
+ Liberty Project
+
+
+ index.html
+
+
\ No newline at end of file
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/webapp/index.html b/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/webapp/index.html
new file mode 100644
index 00000000..d77e51b3
Binary files /dev/null and b/Istio-Samples/bookinfo/src/reviews/reviews-application/src/main/webapp/index.html differ
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-application/src/test/java/test/TestApplication.java b/Istio-Samples/bookinfo/src/reviews/reviews-application/src/test/java/test/TestApplication.java
new file mode 100644
index 00000000..16469c79
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/reviews-application/src/test/java/test/TestApplication.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Istio Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+package test;
+
+public class TestApplication {
+
+}
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/build.gradle b/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/build.gradle
new file mode 100644
index 00000000..9ed93c6c
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/build.gradle
@@ -0,0 +1,19 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+}
+
+apply plugin: 'eclipse'
+
+task copyApplication(type: Copy) {
+ from '../reviews-application/build/libs/reviews-application-1.0.war'
+ into 'servers/LibertyProjectServer/apps/'
+}
+
+task build(dependsOn: ['copyApplication']){
+}
+
+task clean {
+ delete "servers/LibertyProjectServer/apps"
+}
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/servers/LibertyProjectServer/server.xml b/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/servers/LibertyProjectServer/server.xml
new file mode 100644
index 00000000..aac20bd5
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/servers/LibertyProjectServer/server.xml
@@ -0,0 +1,33 @@
+
+
+
+
+ jaxrs-2.0
+ jsonp-1.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/shared/.gitkeep b/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/shared/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/src/test/java/it/EndpointTest.java b/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/src/test/java/it/EndpointTest.java
new file mode 100644
index 00000000..d594d532
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/src/test/java/it/EndpointTest.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Istio Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+package it;
+
+import static org.junit.Assert.assertTrue;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+
+public class EndpointTest {
+
+ public void testEndpoint(String endpoint, String expectedOutput) {
+ String port = System.getProperty("liberty.test.port");
+ String war = System.getProperty("war.name");
+ String url = "http://localhost:" + port + "/" + war + endpoint;
+ System.out.println("Testing " + url);
+ Response response = sendRequest(url, "GET");
+ int responseCode = response.getStatus();
+ assertTrue("Incorrect response code: " + responseCode,
+ responseCode == 200);
+
+ String responseString = response.readEntity(String.class);
+ response.close();
+ assertTrue("Incorrect response, response is " + responseString, responseString.contains(expectedOutput));
+ }
+
+ public Response sendRequest(String url, String requestType) {
+ Client client = ClientBuilder.newClient();
+ System.out.println("Testing " + url);
+ WebTarget target = client.target(url);
+ Invocation.Builder invoBuild = target.request();
+ Response response = invoBuild.build(requestType).invoke();
+ return response;
+ }
+}
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/src/test/java/it/TestApplication.java b/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/src/test/java/it/TestApplication.java
new file mode 100644
index 00000000..de7fa293
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/src/test/java/it/TestApplication.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Istio Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+package it;
+
+import org.junit.Test;
+
+public class TestApplication extends EndpointTest {
+
+ @Test
+ public void testDeployment() {
+ testEndpoint("/index.html", "Welcome to your Liberty Application ");
+ }
+
+}
diff --git a/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/src/test/java/it/rest/LibertyRestEndpointTest.java b/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/src/test/java/it/rest/LibertyRestEndpointTest.java
new file mode 100644
index 00000000..916841fa
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/reviews-wlpcfg/src/test/java/it/rest/LibertyRestEndpointTest.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Istio Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+package it.rest;
+
+import it.EndpointTest;
+
+import org.junit.Test;
+
+public class LibertyRestEndpointTest extends EndpointTest {
+
+ @Test
+ public void testDeployment() {
+ testEndpoint("/rest", "Hello from the REST endpoint!");
+ }
+}
diff --git a/Istio-Samples/bookinfo/src/reviews/settings.gradle b/Istio-Samples/bookinfo/src/reviews/settings.gradle
new file mode 100644
index 00000000..019d1e82
--- /dev/null
+++ b/Istio-Samples/bookinfo/src/reviews/settings.gradle
@@ -0,0 +1,4 @@
+rootProject.name = 'reviews'
+
+include 'reviews-application'
+include 'reviews-wlpcfg'
diff --git a/Istio-Samples/bookinfo/swagger.yaml b/Istio-Samples/bookinfo/swagger.yaml
new file mode 100644
index 00000000..6782e732
--- /dev/null
+++ b/Istio-Samples/bookinfo/swagger.yaml
@@ -0,0 +1,248 @@
+swagger: "2.0"
+info:
+ description: "This is the API of the Istio BookInfo sample application."
+ version: "1.0.0"
+ title: "BookInfo API"
+ termsOfService: "https://istio.io/"
+ license:
+ name: "Apache 2.0"
+ url: "http://www.apache.org/licenses/LICENSE-2.0.html"
+basePath: "/api/v1"
+tags:
+- name: "product"
+ description: "Information about a product (in this case a book)"
+- name: "review"
+ description: "Review information for a product"
+- name: "rating"
+ description: "Rating information for a product"
+externalDocs:
+ description: "Learn more about the Istio BookInfo application"
+ url: "https://istio.io/docs/samples/bookinfo.html"
+paths:
+ /products:
+ get:
+ tags:
+ - "product"
+ summary: "List all products"
+ description: "List all products available in the application with a minimum amount of information."
+ operationId: "getProducts"
+ consumes:
+ - "application/json"
+ produces:
+ - "application/json"
+ responses:
+ 200:
+ description: "successful operation"
+ schema:
+ type: "array"
+ items:
+ $ref: "#/definitions/Product"
+ /products/{id}:
+ get:
+ tags:
+ - "product"
+ summary: "Get individual product"
+ description: "Get detailed information about an individual product with the given id."
+ operationId: "getProduct"
+ consumes:
+ - "application/json"
+ produces:
+ - "application/json"
+ parameters:
+ - name: "id"
+ in: "path"
+ description: "Product id"
+ required: true
+ type: "integer"
+ format: "int32"
+ responses:
+ 200:
+ description: "successful operation"
+ schema:
+ $ref: "#/definitions/ProductDetails"
+ 400:
+ description: "Invalid product id"
+ /products/{id}/reviews:
+ get:
+ tags:
+ - "review"
+ summary: "Get reviews for a product"
+ description: "Get reviews for a product, including review text and possibly ratings information."
+ operationId: "getProductReviews"
+ consumes:
+ - "application/json"
+ produces:
+ - "application/json"
+ parameters:
+ - name: "id"
+ in: "path"
+ description: "Product id"
+ required: true
+ type: "integer"
+ format: "int32"
+ responses:
+ 200:
+ description: "successful operation"
+ schema:
+ $ref: "#/definitions/ProductReviews"
+ 400:
+ description: "Invalid product id"
+ /products/{id}/ratings:
+ get:
+ tags:
+ - "rating"
+ summary: "Get ratings for a product"
+ description: "Get ratings for a product, including stars and their color."
+ operationId: "getProductRatings"
+ consumes:
+ - "application/json"
+ produces:
+ - "application/json"
+ parameters:
+ - name: "id"
+ in: "path"
+ description: "Product id"
+ required: true
+ type: "integer"
+ format: "int32"
+ responses:
+ 200:
+ description: "successful operation"
+ schema:
+ $ref: "#/definitions/ProductRatings"
+ 400:
+ description: "Invalid product id"
+
+
+definitions:
+ Product:
+ type: "object"
+ description: "Basic information about a product"
+ properties:
+ id:
+ type: "integer"
+ format: "int32"
+ description: "Product id"
+ title:
+ type: "string"
+ description: "Title of the book"
+ descriptionHtml:
+ type: "string"
+ description: "Description of the book - may contain HTML tags"
+ required:
+ - "id"
+ - "title"
+ - "descriptionHtml"
+ ProductDetails:
+ type: "object"
+ description: "Detailed information about a product"
+ properties:
+ id:
+ type: "integer"
+ format: "int32"
+ description: "Product id"
+ publisher:
+ type: "string"
+ description: "Publisher of the book"
+ language:
+ type: "string"
+ description: "Language of the book"
+ author:
+ type: "string"
+ description: "Author of the book"
+ ISBN-10:
+ type: "string"
+ description: "ISBN-10 of the book"
+ ISBN-13:
+ type: "string"
+ description: "ISBN-13 of the book"
+ year:
+ type: "integer"
+ format: "int32"
+ description: "Year the book was first published in"
+ type:
+ type: "string"
+ enum:
+ - "paperback"
+ - "hardcover"
+ description: "Type of the book"
+ pages:
+ type: "integer"
+ format: "int32"
+ description: "Number of pages of the book"
+ required:
+ - "id"
+ - "publisher"
+ - "language"
+ - "author"
+ - "ISBN-10"
+ - "ISBN-13"
+ - "year"
+ - "type"
+ - "pages"
+ ProductReviews:
+ type: "object"
+ description: "Object containing reviews for a product"
+ properties:
+ id:
+ type: "integer"
+ format: "int32"
+ description: "Product id"
+ reviews:
+ type: "array"
+ description: "List of reviews"
+ items:
+ $ref: "#/definitions/Review"
+ required:
+ - "id"
+ - "reviews"
+ Review:
+ type: "object"
+ description: "Review of a product"
+ properties:
+ reviewer:
+ type: "string"
+ description: "Name of the reviewer"
+ text:
+ type: "string"
+ description: "Review text"
+ rating:
+ $ref: "#/definitions/Rating"
+ required:
+ - "reviewer"
+ - "text"
+ Rating:
+ type: "object"
+ description: "Rating of a product"
+ properties:
+ stars:
+ type: "integer"
+ format: "int32"
+ minimum: 1
+ maximum: 5
+ description: "Number of stars"
+ color:
+ type: "string"
+ enum:
+ - "red"
+ - "black"
+ description: "Color in which stars should be displayed"
+ required:
+ - "stars"
+ - "color"
+ ProductRatings:
+ type: "object"
+ description: "Object containing ratings of a product"
+ properties:
+ id:
+ type: "integer"
+ format: "int32"
+ description: "Product id"
+ ratings:
+ type: "object"
+ description: "A hashmap where keys are reviewer names, values are number of stars"
+ additionalProperties:
+ type: "string"
+ required:
+ - "id"
+ - "ratings"
\ No newline at end of file
diff --git a/Istio-Samples/certs/README.md b/Istio-Samples/certs/README.md
new file mode 100644
index 00000000..847d60ab
--- /dev/null
+++ b/Istio-Samples/certs/README.md
@@ -0,0 +1,38 @@
+# Istio plugin CA sample certificates
+
+This directory contains sample pre-generated certificate and keys to demonstrate how an operator could configure Citadel with an existing root certificate, signing certificates and keys. In such
+a deployment, Citadel acts as an intermediate certificate authority (CA), under the given root CA.
+Instructions are available [here](https://istio.io/docs/tasks/security/cert-management/plugin-ca-cert/).
+
+The included sample files are:
+
+- `root-cert.pem`: root CA certificate.
+- `root-cert-alt.pem`: alternative CA certificate.
+- `root-cert-combined.pem`: combine `root-cert.pem` and `root-cert-alt.pem` into a single file.
+- `root-cert-combined-2.pem`: combine `root-cert.pem` and two `root-cert-alt.pem` into a single file.
+- `ca-[cert|key].pem`: Citadel intermediate certificate and corresponding private key.
+- `ca-[cert-alt|key-alt].pem`: alternative intermediate certificate and corresponding private key.
+- `ca-[cert-alt-2|key-alt-2].pem`: alternative intermediate certificate and corresponding private key signed by `root-cert-alt.pem`.
+- `cert-chain.pem`: certificate trust chain.
+- `cert-chain-alt.pem`: alternative certificate chain.
+- `cert-chain-alt-2.pem`: alternative certificate chain signed by `root-cert-alt.pem`.
+- `workload-foo-[cert|key].pem`: workload certificate and key for URI SAN `spiffe://trust-domain-foo/ns/foo/sa/foo` signed by `ca-cert.key`.
+- `workload-bar-[cert|key].pem`: workload certificate and key for URI SAN `spiffe://trust-domain-bar/ns/bar/sa/bar` signed by `ca-cert.key`.
+- `workload-foo-root-certs.pem`: root and intermediate CA certificates for foo workload certificate.
+- `workload-bar-root-certs.pem`: root and intermediate CA certificates for bar workload certificate.
+- `leaf-workload-foo-cert.pem`: leaf workload certificate for URI SAN `spiffe://trust-domain-foo/ns/foo/sa/foo`.
+- `leaf-workload-bar-cert.pem`: leaf workload certificate for URI SAN `spiffe://trust-domain-bar/ns/bar/sa/bar`.
+
+The workload cert and key are generated by:
+
+```shell script
+ ./generate-workload.sh foo
+ ./generate-workload.sh bar
+```
+
+To generate certs signed by the alternative root `root-cert-alt.pem`
+
+```shell script
+./generate-workload.sh name namespace serviceAccount tmpDir use-alternative-root
+./generate-workload.sh name namespace serviceAccount tmpDir use-alternative-root
+```
diff --git a/Istio-Samples/certs/ca-cert-alt-2.pem b/Istio-Samples/certs/ca-cert-alt-2.pem
new file mode 100644
index 00000000..afd02209
--- /dev/null
+++ b/Istio-Samples/certs/ca-cert-alt-2.pem
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFeTCCA2GgAwIBAgIUNnd90WzsKHfAhOFJAiow2W5D8iQwDQYJKoZIhvcNAQEL
+BQAwIjEOMAwGA1UECgwFSXN0aW8xEDAOBgNVBAMMB1Jvb3QgQ0EwHhcNMjMxMjEx
+MTYyNTMwWhcNMzMxMjA4MTYyNTMwWjA9MQ4wDAYDVQQKDAVJc3RpbzEYMBYGA1UE
+AwwPSW50ZXJtZWRpYXRlIENBMREwDwYDVQQHDAhjbHVzdGVyMjCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAMbK7UmbUiCLkoUMUXE+5gkfHQ/x808O/RfL
+JNxUa/1pN6Jt9COosld69FmJBwpTufOyCZOP7rerOeufxlel45R28EVNyRnjG6jO
+Kl/O1vuAwjc0HNvftXTsYVEZ+zpV4UWa4QK6kUwIZ6KH75A6HT6qmJavNEs1PEUA
+oCitowAMpn8Ix1E9LxQNgx7IUeAD8THzyeAPZsOYcl1IFWvZkcqabg9hMqXtPxP0
+eciHlQb/jeEd0gLTXVi7ymhUczMmffxZZrQ346Ylz7zZ6SkHFjPCyfeNSwB5iszk
+VdKGVtyogmp7mEcwa8o4p1JESmWF3qRZpUVs+Y7loGYTVQBlqUSdnI/zx5yd+qXY
+mR3ktEUK5AUI7liIwJ1BKZy6z4OSZ+qna+LbJRqLcB/4tK0YuOf8ffmk18GyjQQ+
+tKeZjntTnnaS+mtFLP1zpW+BnurCRfVPxEg8bFCg511AuyuWRuB2MHQXQg+H915C
+e2qm5/ccGfV2mDVF2jKS1q39g7YVLd5HCxR0rBlrh9IwdxE5sAzoREylLrc+HsJn
+27841ID+MiwI3l/GUst/UW2SEA1OtxT5USC6pkZyRBM/Y7OJthNxXyCOpzUhu8AQ
+GUbtrdI7oEFaSLsdH2GXhQeh0TecJiNnhbvIryZK2HofWncdBVE+AcK7VWUFO4At
+6gVcR1qPAgMBAAGjgYswgYgwHQYDVR0OBBYEFCuu9MuphtLDKUZpJK49m12qXRwo
+MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgLkMCIGA1UdEQQbMBmC
+F2lzdGlvZC5pc3Rpby1zeXN0ZW0uc3ZjMB8GA1UdIwQYMBaAFL3svuf0yV+M2BHp
+EvDmo37j045gMA0GCSqGSIb3DQEBCwUAA4ICAQDGvZxypjwVUljjvQ1AFi6Grirq
+iLPgrC5zepLyUaWefLr9I99k4Uq8+f5WWk3Y04SWnY2JPNGvdjAG8aRpM0IixnO0
+OFnlaYjRBv0EKhdzg+TC6O9R2s5s01lR4ya1kmzDyC7BKcGzo8T2IXOOTftcFAAT
+arc6Z55BuFuYslWlj+bQ96mxuN1q53a+JzYl+o92vpdnCBKb3OSGjb1hA29E3wzm
+YPsctkItuGImX/JUBqZH/0YxdRDjXI8AJ8R8p1qoZZORMrMVey8bX98EN3ai8HVQ
+RmP1Fa7qU3O28fi5JHGaX48O8VdJHdRR0G87qDNxArtrhrylrcTykPZkapwUQP+C
+SJuy2F5hEVwI8nwX6SKbzW3tsUYQssk9/3U4DmfIWhCg7ffeEp+aLshkrtlIi9NY
+YZtznntQagFSs3Cg/XsSjcKMmVfQ69uy7tTHUpK66mz5DosRBo13DFaI19bxNfQX
+yJnKuuvyx1q6Y7BsFwqElX2G9WZ6/mgUpochDKgTni0o6AmDBvrfcXfJRxQwICUe
+crvOngDaRmQ50HaKoNtWgYHYCXSNP8de//Yz+ebusyLca4i0PTt5oGInW4k8folC
+ntXpODzLE3qNYRrSM74KGNre7hwp9BE+i6ksiojVawt5GJgS98PK3zdpVNNIPp0s
+ZW8HVio+HD4I2VBxTQ==
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/ca-cert-alt.pem b/Istio-Samples/certs/ca-cert-alt.pem
new file mode 100644
index 00000000..f20a8c6e
--- /dev/null
+++ b/Istio-Samples/certs/ca-cert-alt.pem
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFeTCCA2GgAwIBAgIUQchu+RczGG1A4BnmrCcpkURQGTAwDQYJKoZIhvcNAQEL
+BQAwIjEOMAwGA1UECgwFSXN0aW8xEDAOBgNVBAMMB1Jvb3QgQ0EwHhcNMjMxMjEx
+MTYyNTI1WhcNMzMxMjA4MTYyNTI1WjA9MQ4wDAYDVQQKDAVJc3RpbzEYMBYGA1UE
+AwwPSW50ZXJtZWRpYXRlIENBMREwDwYDVQQHDAhjbHVzdGVyMTCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAJCkq9Y68g9n0i4xkyYo4mygXIgaj94cvmu3
+X81CLEu/hYrl08acaKZMno+57ibAfxKBsWfA0FMp1eXZ3T9KYlNsSarC8c6RCPbX
+Lzp4iPGMq5n/+OgCGaVUbaLuZB7F6gCJebyM3Du6Zap7X1xm3w2EpiVqHW6iAJqv
+oBNtm7/uzFQiIU3UMeea/XBzo1FpDqNcuc/GgyILs1GA2+U4LfmcwhvUjF36bZ1q
+WMnPfCMHwHTNiGikAJKSXqADz8+rthOyNZq3yFGV/ZOJf6yHOWiyP1BjojRbHCt1
+P8u2nWuD40iqreVrQw3h5Hsz6+mCIkUYFZ45yO0fyRZ/q46M8RKHluD1VI7X6R98
+wB+XPqh12tbXUQJw1/QdtUotszhQq/WUbewX9v4joGIel3MFpoBCoaHh4N4/S1Vk
+9k32c4lEYeV5wO6DZSV9fuasN6KzaiPNNiufP2MnIzJSbal0uZJ0dmyhmHGLGsGc
+t6zxAQpV8reqWZE1mZt94T4TnDpm61BDKRPRu7s6sP42iq6055c+5x3DhVqTInnB
+uTi7oikTykZ2s0budYyjATNMUuz2RHZXxfb6ScqC5mEL0kbKCDgRzS0NS15LHpUX
+Ue65PG8hiuWLuDTcQohWFkeIQyKUGL9uQ5qmmGK8FZwUU/9gY1JjrMw5sa+rVN/C
+hkbRsHmBAgMBAAGjgYswgYgwHQYDVR0OBBYEFP/KjsSWWC+hw1cIaZLn1ZV3IeMq
+MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgLkMCIGA1UdEQQbMBmC
+F2lzdGlvZC5pc3Rpby1zeXN0ZW0uc3ZjMB8GA1UdIwQYMBaAFL3svuf0yV+M2BHp
+EvDmo37j045gMA0GCSqGSIb3DQEBCwUAA4ICAQBO6P+y7UQ7HRyA7dOf2Dvze6xv
+HKgjh8z5uKNbfvmgUT2gECQ+3g0LvDRYHU7w/isSmhCQxIGf+xc7r3+Rtyjg+uEc
+8z0UBysbqrn8pZXPr+FPU5X5czUnwXlZwj02e1fY250LCmfHXFYuPzgwtlbJs2Ec
+2exDG7EZWWX6l/mRFQR8HiF/jum2i06yjO1v+phUVenW/ym2fq+/lY/ZWebQasD7
+7PT3yT/Eage4AIj5zYmZzqJex3OKDiVltAUefnekFJBKqv1UIcWlijRPZPK8uYQk
+IYHRL5fpa9E/HkwY8QopXPJi6Yfx76acY+dQd1xovY3noUVGzQV5wuaICS9V6H9B
+5vkxDYbbABQQ9OJcy8XR7cqlkUATiH5hVRjMSKJiostO+CiVDWjZyJdNgR0kZeaa
+9cSYBdTBxN82A/Vtq4ETq/PG5rR08KQY4HqIlOlo16OxGcJ2zVKSk5lTeI1wx/in
+uOnJTo5mDJHOJrtYGuCLiqZp/Fbcz/Tb9Qccc1yw78feYiNV6JXKx3uPvfsNbXkY
+KnsorT6OQ9G2d/zKPYUw+JEc1BJpk8okvGT8oTfvnfXty63ccN4+iyohQP/GwtQ9
+XiIJ0gGGQjY1VA/L2MOYV0hSMLgddvl4Pt8KXsxQ72gGl8a/s1oOKkYfpm/xchpd
+3ldrrKbAwExwhsARrA==
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/ca-cert.pem b/Istio-Samples/certs/ca-cert.pem
new file mode 100644
index 00000000..a460e036
--- /dev/null
+++ b/Istio-Samples/certs/ca-cert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl
+MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD
+QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx
+OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT
+CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x
+ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9
+iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z
+APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K
+M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom
+ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8
+LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T
+BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC
+AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w
+A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8
+PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y
+05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN
+Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn
+aFKltOc+RAjzDklcUPeG4Y6eMA==
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/ca-key-alt-2.pem b/Istio-Samples/certs/ca-key-alt-2.pem
new file mode 100644
index 00000000..f6e2468d
--- /dev/null
+++ b/Istio-Samples/certs/ca-key-alt-2.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDopeTrevAe/mV+
+rXUNjxsamaQgQ6GQuHlsysUxO9MfMo6jn/v55KZv8LvjRTQXsxT7SIY5UPAcDXUZ
+So866W4kIncUFuIFCvRQfULcP0/dVz8Al1tcssyi5s5rEnUIb8QmCXpM3g7cTONz
+taBSwmY8JG+EjNkUJzFzlWOdMa9kvR2DboWhTnKazM8SUCa7gQDCI0ntZkbFotqx
+uqIkbsxYpgw2mplEGoEcVbfBID2MYqoK+w5CtNGBsnr946auIb33smqtnAC52fyC
+xwoDu3I9XLJZmYEPqk/EyP6cTmxRT3E4SSTGtgEqS51L+eraubpDUBwoW5NPkKah
+qRhaia/26nCMB29WVvSWOfnIb8irZF+Gaq7tWsGY3oZ0o4VWXLmhxMBeeHGhy6Zu
+RID6lE2HCj/LJCChKAThwGpLn2P+9TYiAHjrP8A47SRUq+evKWPgUtOgnF7plgGk
+1WafZt9kIxV0+tptoqquUoMgOT1StBsFRHjUIEk4ABHSZ83y1U61T5AnmVWWfArf
+bsBNYSRRAFU3fD9aIF2RqNlYxCezxoMZaNC7hyqD4vrH+yTsJxuFVgUo+iSYtIxa
+jeJODKtUv0x1sxzhH3JhQ/I2Gk8fby3HEC21eHit69MU+qDQQ69xApY28qk3uEE0
+whzxBAmdqWuWMOkdM4dQpq93vqaJRQIDAQABAoICACZ9FY2AofuarjtiInibCYqh
+yvWcgrzwzAPb2vo9cbzaTh9TTypFMeTYkJj1oLvgAHNfCPewBH07m7kSrPX72uEn
+A4jDDWL0sD0lr/tEjSeq8K0eHTsNiI3VveYYYFzEMtDxJfbUEOTQ4ptIu8ydRTEj
+fQCSlbJAFq4O07NUnjX+FIUjMn/gfNTP190pffLs0W2MzYT1M/Wr7t7S59K7stpi
+pCgfdQY/lUcVBkiw1wXj58pXxQDzrap1luPsdu2dfvJc5cmxgqw8nEodeDJsXya4
+MHhizSeEj1xYvUiqL8DW8f30Gd23DCPNbSk94CUN73sF5JanqcwSvAKIOVN3LnFM
+DrGnvMi4Quct5rBEVsZW7mKdgmNd0rPCjAbQKY3T3HyQuAm/gR0rEv3x4WOvFK2m
+SgPpgcrozNvP9RUgZlziNkdl9iVlnpi/bOAk2VKbQWhArOTolWiEJDNcKOsAQXUj
+JuTEEfv2z9adbguhIL7A79AeqsdJze7YBSqvZcmxVg8FOvQlzlMnznQIfMSTniS2
+CAIEmxPqQ6EQLjMSyDoDdQ5UFQ62MAoG3XGkI9iUQLSsaqY6GBVBJVpAGfbQed/c
+6HAxwdJBw5270Z0xw+U4gTuaG8qDvHHqqO6M9YIjsKAnkwjwGmF1l6HHFFsr5Hyc
+8ZdOGuBV5KBne3vVkmXxAoIBAQD4FTx5vLwdbILvr0ehxLfIH3jxsfF8Dphqb1g0
+tCaiKMEqaeLaKTBxy+h9Z4qfXDQW+3Oa2CZgAbDc2bCJynQ/li5lDGwXlFwnuzPV
+Dq8mIOymogZFgX+WbDDLOJ7rNrj7+82WV4UHZVlDQ3/5zkvJ2GuVICV9MAr1b2c+
++1y0ozE87wViQDuBlHxLDHL7OZq0UinBlAJ0eyPWn5ZjkhxKHqqcDBKjbYm5JgV+
+GhNvNeJZcLUUkmg+MCPMglZ0SJojDBiLVBE5m1S8x+vyoy4bjb0GWag2rapqkCbv
+5X/WqMrVxZdB1X86d4hLFaDwG7yNZtnijJigdFwS+EayE+rVAoIBAQDwEo8ofTZa
+hoY5Fl8KNigqEP5/5n24q+qZ6Ku+SkWBnqmGS5ZHx7u6aItXWc/m9MoZh/jLlbba
+LNCqT1MKa4jLkVVkyUBTqFy4bu3baU1BYHE0zLEkegsb8RnD3tFGI4tjEoBnvwEq
+yQItbQp9IhGTw60fml619WU2yZK5gfIYxBxJyT8M33aizYRSGP2ihBtwFz16/L33
+If0nA30RD2hOXcSGAfoyAn7nFqQfTkByTsSTp8HrqtHLDrTLNDSewx09c2ExuXPd
+XdcXVvA6Z7ZP/vpVrqkLQHVx4dpPsvKQ7rwI0KKjjkvEh/XkJq4xUlPlyMrVkULX
+EFPXHGNhmnyxAoIBAQCmEKEg5KQQFjk39N9AfIyBm/+72t/JqYOBi/NBpG5QEnPr
+zmGapAPXySVh/NOghXohAEWMm7Bkh/06eUZhlnJmtkNsRPp+dkOSHRA/SMsZ/OQt
+TzxffqZHrTikcMyAq2r80rv2LbPRFZjBHAgo0l2NSiAJ/TDbMjPDw8UbNewCx1MI
+dP/nmxO6VAk3u6ekYBUdK/rjqA5UprGA0+c50+639vtB5hr75zFQDRGULiRgR3Oz
+Z2zvzmmVZ2gvV/hDcu4rE8fCTI4TP9VjYXiiPXV54FFuVMnzgCEZoFFQORJwQSE2
+JERyP1Yhby5/BIVs9UQsa3Li4jaxAfM4h5XbUtXZAoIBAQDPCrJ78MCXgbzwLuL4
+I4yv+sgB9f4m7dz9rzOugM9A4lzBfR61+QNl2BOT2dj7DdHeAu4GZa+0qUGsH402
+R1dKeKR0rzvS6jhMtx5bQ41k/I+lQYLkOnyqNFxMGDXTj4P+hU5IKuoOxBwkoQ2S
+rXcLQI5l2vQjaOdJQL5RTkhEI51h5TWDHJVsAmJDi1nydoxTNzfGgYIzSBTTOKb7
+t5X1P9jk2X+08YIQOe6BMTNTYasWzG7pmAAmZyB0vylCYnMtM/x2rcHG/88oScoU
+FK2ef//VNTSEh6rB9E4avfGEHN/9mjEpbObbL4ZYpSNFVgMVAP4tAYHriCFGOy1a
+V6mBAoIBAQDVG3hZJ8jONTpW4EXLrHIWtgxhYNjIdM3EFPFLZtMQ3ub6iNwtfMeM
+fjD4CJGRIK52t4jv65F0lY8p4JFGLVjnXIIxP45/GZ4CGj+APg4dBd5cORmJmuZQ
+jzJyHJ1/Oc12v1VMb7HJRezeAm60wjGKr1PeFezp2HkjQDNswwSvjmbQhIYvIII+
+l5RosqYuIPYq96+L4gj4VSh4IfbUHt0fY6O90cjdHK0fbXL99GtKMJvgA4u9IKDb
+FwimOxL+xU8CeBV8TebVS5NYyyPHoKNkGh5GDNkKFG4e75Qn04P+vRvn/CJaz2Vt
+f9ijIRn01xKm7QpucsEmo6FNo58miyT9
+-----END PRIVATE KEY-----
diff --git a/Istio-Samples/certs/ca-key-alt.pem b/Istio-Samples/certs/ca-key-alt.pem
new file mode 100644
index 00000000..3f1f1964
--- /dev/null
+++ b/Istio-Samples/certs/ca-key-alt.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCQpKvWOvIPZ9Iu
+MZMmKOJsoFyIGo/eHL5rt1/NQixLv4WK5dPGnGimTJ6Pue4mwH8SgbFnwNBTKdXl
+2d0/SmJTbEmqwvHOkQj21y86eIjxjKuZ//joAhmlVG2i7mQexeoAiXm8jNw7umWq
+e19cZt8NhKYlah1uogCar6ATbZu/7sxUIiFN1DHnmv1wc6NRaQ6jXLnPxoMiC7NR
+gNvlOC35nMIb1Ixd+m2daljJz3wjB8B0zYhopACSkl6gA8/Pq7YTsjWat8hRlf2T
+iX+shzlosj9QY6I0WxwrdT/Ltp1rg+NIqq3la0MN4eR7M+vpgiJFGBWeOcjtH8kW
+f6uOjPESh5bg9VSO1+kffMAflz6oddrW11ECcNf0HbVKLbM4UKv1lG3sF/b+I6Bi
+HpdzBaaAQqGh4eDeP0tVZPZN9nOJRGHlecDug2UlfX7mrDeis2ojzTYrnz9jJyMy
+Um2pdLmSdHZsoZhxixrBnLes8QEKVfK3qlmRNZmbfeE+E5w6ZutQQykT0bu7OrD+
+NoqutOeXPucdw4VakyJ5wbk4u6IpE8pGdrNG7nWMowEzTFLs9kR2V8X2+knKguZh
+C9JGygg4Ec0tDUteSx6VF1HuuTxvIYrli7g03EKIVhZHiEMilBi/bkOapphivBWc
+FFP/YGNSY6zMObGvq1TfwoZG0bB5gQIDAQABAoICAAOg1NRkMMKbCyg4W0GEmqbo
+yB9sIqYavJpTPIyHm5i4FHmLKbJ4hY2/2+WdL2ySjTF1tkF08kjWwqBAFHsgIpqm
++4tUdeg1hkb6V3uBDubXvW140LmhpVrqxPAGiLWGp4e1SxvkIOlg4+hYjUgiJrfW
+JyyGtpeqCce3jnV0TTkNnHujCkizcR/HGRLFPNBXyTum8ZyFFVChIGGz0LhFji4t
+7ObRsGZyV+XwJytjSHDwwqavaeu9iuviTuw2wkOKYjAo6wwvLl/BCl4FP8IQN4wB
+NiI+KJFFhI2wxI2XrmfWNGkkCmYICHPggeinARS/vFw1NiQcnRYZIzQ8tj0GeyzP
+FeC4ozplVdsp4ouY1/XsyoW1vG/gRLV+ua3dQyHPreLAP452QGOhzffUNksCejtb
+dPQJ5e4RZeAQab5YL2MSNCutZ/tcGJtsjuiSfDZZflWEeKpXz/NU4WiGxX+AHC6C
+TIscYhXbCkanZ6J5UXOwVjUsg2xLcuAyoh67iphMuqTbaeQSJehPwhkR4VXad9mW
+1ChZJnc/YSD6S3/fGzSn94kWWDCoRh9KUtqk0ZCRJBQdHq9owPny0tszxJZZw6wF
+6nnQH8Ywk5RsvNL2CxMWFuPIfPgUuoSgucBpWoHmcN7ZRWsd+wfZsolbZtE09buz
+mUXybkHnWtMUO3MlJoARAoIBAQDK7E9ZExt4GGsyvWAw2HVuHJ0VF5LAlvgHGiHj
+r2zDw7mWX9jIMnZcB3s3DJFIZloQspDyxrIwefuI2xTHpoI4yeTH/MWjyzaBhZAW
+uMDakWuUTFXYfPPrLorLh7HwMYGxJoI5Gx9bvTHs/Gl/3KwNsX6kWayCTruvUfuH
+5uOKZd3XvjgfcUT9uKnOf/K8eJDZ2d4LIDm+VkCSsU832CsPMf1O0wLGe1QEiaAt
+PXHyxF5wnNn3URYmtukyX4gspI9ZCqu6cYOYdvuwl6XihaFD812eUtnaNc5b8BQH
+5/INKNvZrPmcjvW2LiPqHFfnG8gvcZ++hy/poG48/5K7/k3RAoIBAQC2efRnqHxi
++mPDCytVdI1egkMZzkfq8syzPKr1zE6fDCizYuIGl00SJOVvm0avFz0z+mBT2cGl
+xYMe36XtkLZ7qt0g95M/8Obt1EZvOJ5AGgjFgOCD3BPK1W/CdXP+Aa1HKb0LrUak
+VRfARWjDvF97q2BANyWRy4mfRHcgQbXDcuSG4iyUP9IPZWHtt13CTrkM0zbawFb/
+nx1tmLCXT4N+s3h3PgB6+TpolWuZX1Sxbkggf4uQwZrwrcuDF+F9pbgQ97oeNmmP
+BSZoh0YG9COdVxTJ5nqFYKKenLl3PVG5SADBrW5Hftax2bfijq/UdwolwLWc26uV
+y05jJ8odIOyxAoIBAF1bYJoDX2TeHxtl4sY2H7h784zLnpl6GzvxOtwsTea2ukBD
+clGQXcGzM229G23qoM8DyAnZfgstY5qv6Bx+L3T+9YFIeokDqdzm3MaHUzp7IrpE
+cE48FmABtpsyn5t4u0kMBWdOYhvrq/dynPrVRFa8bR4hn2sH2/MpzYXVpKN8gBaM
+jfdxPiNYfM7jMIKjGUkQocYOmmJF/kk+x8pSamUAQ6CrFaDJBntb8dQ+a5kb3LME
+hobwyDcheaHSL60SPFzjuuP462kOfHbfHdNcVTgU0+JODaoFjR3hEuYcQNDrFlJL
+8T6kysh4687+ITbTIkMpjCu0uEdMpsrrbc+NjLECggEAPuxI6iHAWsUq94v3cm1R
+fmB+0Pw/8nWtPrVR4paEGfYwZsNXW5x62CHe+CBcPG5QDYduBhwV2ZsFPvUyG3yG
+YJinzgFxRmBE0YgcjafBcitIEQsC4JVYQd5dvnmP+OwNG3f6F3e13170ZLnKiYyA
+hH2xIBOkIeVE3KXYSkg+bFpHEXgWlTx4rBRys21CqIlK6HBA/yfKGDV/CVbYtiSW
+HG+4v62irsUYbg3wX5/u7Yww1PwGXXFVg176yYbHm/M0SK2UAW0T81x8RRk4fZdc
+XJo1sfWHFE0hZn52ufZsIu8AS8kJOSA02nlQHpDDcwlld2U/ewqI3YuQyUJkQK0k
+0QKCAQAdJtr4fvDtghvum7+ZYkzmt9kstm4/elM35FmAtJfm11DQJ4bSTErrj+Zz
+zQOJ0P8VF0MFoFoCuUPoN5u2eq3Y0na6DhD4RqYJA9BkZFrKqn8U33CgX6qQ7UHC
+P3WuawYeR3xBdIKPUGOMPdUiwfC6Xz9JL2L0WcnoGQ3rI3AhijvyF4r4F3dCycZy
+IM5LZJWsTOhCJqOuxrAQLJz2UX28+Bn7gH+jPTZLKE2yX3NH9/L0ydqwZLjFw3e9
+I53RcJBti1zA8N0n8IISOlwiKnhUiLyrujccEYzQFDVyjvcGos68gNLEXPPOceq1
+8xj8Qh/Q3Y4H3Ktn1ELiSPHc44oM
+-----END PRIVATE KEY-----
diff --git a/Istio-Samples/certs/ca-key.pem b/Istio-Samples/certs/ca-key.pem
new file mode 100644
index 00000000..faa77f38
--- /dev/null
+++ b/Istio-Samples/certs/ca-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy1
+3XIQk8/u/By9iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3Hzd
+Rw+SBhXlsh9zAPZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSd
+PrFx6EyMXl7KM8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLs
+ar69PgFS0TomESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJ
+t/h8yspS1ck8LJtCole9919umByg5oruflqIlQIDAQABAoIBAGZI8fnUinmd5R6B
+C941XG3XFs6GAuUm3hNPcUFuGnntmv/5I0gBpqSyFO0nDqYg4u8Jma8TTCIkmnFN
+ogIeFU+LiJFinR3GvwWzTE8rTz1FWoaY+M9P4ENd/I4pVLxUPuSKhfA2ChAVOupU
+8F7D9Q/dfBXQQCT3VoUaC+FiqjL4HvIhji1zIqaqpK7fChGPraC/4WHwLMNzI0Zg
+oDdAanwVygettvm6KD7AeKzhK94gX1PcnsOi3KuzQYvkenQE1M6/K7YtEc5qXCYf
+QETj0UCzB55btgdF36BGoZXf0LwHqxys9ubfHuhwKBpY0xg2z4/4RXZNhfIDih3w
+J3mihcECgYEA6FtQ0cfh0Zm03OPDpBGc6sdKxTw6aBDtE3KztfI2hl26xHQoeFqp
+FmV/TbnExnppw+gWJtwx7IfvowUD8uRR2P0M2wGctWrMpnaEYTiLAPhXsj69HSM/
+CYrh54KM0YWyjwNhtUzwbOTrh1jWtT9HV5e7ay9Atk3UWljuR74CFMUCgYEA392e
+DVoDLE0XtbysmdlfSffhiQLP9sT8+bf/zYnr8Eq/4LWQoOtjEARbuCj3Oq7bP8IE
+Vz45gT1mEE3IacC9neGwuEa6icBiuQi86NW8ilY/ZbOWrRPLOhk3zLiZ+yqkt+sN
+cqWx0JkIh7IMKWI4dVQgk4I0jcFP7vNG/So4AZECgYEA426eSPgxHQwqcBuwn6Nt
+yJCRq0UsljgbFfIr3Wfb3uFXsntQMZ3r67QlS1sONIgVhmBhbmARrcfQ0+xQ1SqO
+wqnOL4AAd8K11iojoVXLGYP7ssieKysYxKpgPE8Yru0CveE9fkx0+OGJeM2IO5hY
+qHAoTt3NpaPAuz5Y3XgqaVECgYA0TONS/TeGjxA9/jFY1Cbl8gp35vdNEKKFeM5D
+Z7h+cAg56FE8tyFyqYIAGVoBFL7WO26mLzxiDEUfA/0Rb90c2JBfzO5hpleqIPd5
+cg3VR+cRzI4kK16sWR3nLy2SN1k6OqjuovVS5Z3PjfI3bOIBz0C5FY9Pmt0g1yc7
+mDRzcQKBgQCXWCZStbdjewaLd5u5Hhbw8tIWImMVfcfs3H1FN669LLpbARM8RtAa
+8dYwDVHmWmevb/WX03LiSE+GCjCBO79fa1qc5RKAalqH/1OYxTuvYOeTUebSrg8+
+lQFlP2OC4GGolKrN6HVWdxtf+F+SdjwX6qGCfYkXJRLYXIFSFjFeuw==
+-----END RSA PRIVATE KEY-----
diff --git a/Istio-Samples/certs/cert-chain-alt-2.pem b/Istio-Samples/certs/cert-chain-alt-2.pem
new file mode 100644
index 00000000..ba9e49e7
--- /dev/null
+++ b/Istio-Samples/certs/cert-chain-alt-2.pem
@@ -0,0 +1,62 @@
+-----BEGIN CERTIFICATE-----
+MIIFeTCCA2GgAwIBAgIUNnd90WzsKHfAhOFJAiow2W5D8iQwDQYJKoZIhvcNAQEL
+BQAwIjEOMAwGA1UECgwFSXN0aW8xEDAOBgNVBAMMB1Jvb3QgQ0EwHhcNMjMxMjEx
+MTYyNTMwWhcNMzMxMjA4MTYyNTMwWjA9MQ4wDAYDVQQKDAVJc3RpbzEYMBYGA1UE
+AwwPSW50ZXJtZWRpYXRlIENBMREwDwYDVQQHDAhjbHVzdGVyMjCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAMbK7UmbUiCLkoUMUXE+5gkfHQ/x808O/RfL
+JNxUa/1pN6Jt9COosld69FmJBwpTufOyCZOP7rerOeufxlel45R28EVNyRnjG6jO
+Kl/O1vuAwjc0HNvftXTsYVEZ+zpV4UWa4QK6kUwIZ6KH75A6HT6qmJavNEs1PEUA
+oCitowAMpn8Ix1E9LxQNgx7IUeAD8THzyeAPZsOYcl1IFWvZkcqabg9hMqXtPxP0
+eciHlQb/jeEd0gLTXVi7ymhUczMmffxZZrQ346Ylz7zZ6SkHFjPCyfeNSwB5iszk
+VdKGVtyogmp7mEcwa8o4p1JESmWF3qRZpUVs+Y7loGYTVQBlqUSdnI/zx5yd+qXY
+mR3ktEUK5AUI7liIwJ1BKZy6z4OSZ+qna+LbJRqLcB/4tK0YuOf8ffmk18GyjQQ+
+tKeZjntTnnaS+mtFLP1zpW+BnurCRfVPxEg8bFCg511AuyuWRuB2MHQXQg+H915C
+e2qm5/ccGfV2mDVF2jKS1q39g7YVLd5HCxR0rBlrh9IwdxE5sAzoREylLrc+HsJn
+27841ID+MiwI3l/GUst/UW2SEA1OtxT5USC6pkZyRBM/Y7OJthNxXyCOpzUhu8AQ
+GUbtrdI7oEFaSLsdH2GXhQeh0TecJiNnhbvIryZK2HofWncdBVE+AcK7VWUFO4At
+6gVcR1qPAgMBAAGjgYswgYgwHQYDVR0OBBYEFCuu9MuphtLDKUZpJK49m12qXRwo
+MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgLkMCIGA1UdEQQbMBmC
+F2lzdGlvZC5pc3Rpby1zeXN0ZW0uc3ZjMB8GA1UdIwQYMBaAFL3svuf0yV+M2BHp
+EvDmo37j045gMA0GCSqGSIb3DQEBCwUAA4ICAQDGvZxypjwVUljjvQ1AFi6Grirq
+iLPgrC5zepLyUaWefLr9I99k4Uq8+f5WWk3Y04SWnY2JPNGvdjAG8aRpM0IixnO0
+OFnlaYjRBv0EKhdzg+TC6O9R2s5s01lR4ya1kmzDyC7BKcGzo8T2IXOOTftcFAAT
+arc6Z55BuFuYslWlj+bQ96mxuN1q53a+JzYl+o92vpdnCBKb3OSGjb1hA29E3wzm
+YPsctkItuGImX/JUBqZH/0YxdRDjXI8AJ8R8p1qoZZORMrMVey8bX98EN3ai8HVQ
+RmP1Fa7qU3O28fi5JHGaX48O8VdJHdRR0G87qDNxArtrhrylrcTykPZkapwUQP+C
+SJuy2F5hEVwI8nwX6SKbzW3tsUYQssk9/3U4DmfIWhCg7ffeEp+aLshkrtlIi9NY
+YZtznntQagFSs3Cg/XsSjcKMmVfQ69uy7tTHUpK66mz5DosRBo13DFaI19bxNfQX
+yJnKuuvyx1q6Y7BsFwqElX2G9WZ6/mgUpochDKgTni0o6AmDBvrfcXfJRxQwICUe
+crvOngDaRmQ50HaKoNtWgYHYCXSNP8de//Yz+ebusyLca4i0PTt5oGInW4k8folC
+ntXpODzLE3qNYRrSM74KGNre7hwp9BE+i6ksiojVawt5GJgS98PK3zdpVNNIPp0s
+ZW8HVio+HD4I2VBxTQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFFDCCAvygAwIBAgIUbQ/RQ9GNnLx7rNVNUJHeizdO1TswDQYJKoZIhvcNAQEL
+BQAwIjEOMAwGA1UECgwFSXN0aW8xEDAOBgNVBAMMB1Jvb3QgQ0EwHhcNMjMxMjEx
+MTYyNDM2WhcNMzMxMjA4MTYyNDM2WjAiMQ4wDAYDVQQKDAVJc3RpbzEQMA4GA1UE
+AwwHUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAN7V2l7b
+/bZsHlWY5qC1p99Au3I0VYr34i/2BIMHSnh1jHn1B6qspjHw2IkqH0SU41M3Vpr7
+m06HGuuZHsq8biUfuUL6Ywt+Vyj2UnPuc6SDPRXxAkBaVGGEAs30akJPkhbbA2qv
+jFxfc2A8GCfnHpGYQkZOvZEQNeHPYkTDsdLEKdbdXkzJMFEGxGDgYiW7xjowDkta
+YlrLBIeHwRCnZ/gTjdCu6oPjCW9JsySbbfx8dYWthIDf/SGqnX8gnDn5K1W5Ip+w
+xaiXZ9FsEzrWd+DXx67sPAS2wl/Qe+RVFLbCGfGnfKdj0CGUtwV/hE2BLWk7fMK/
+dzQR9Bc6GM06uJejZFGuVrwkJldzWW7rp6cJc5D5vJxYCRZZsuk3x6o/mg+z+meh
+kYeUCgsEGU1eKJB7tJ6myiYCLvgjihnnbS0fQlq+9XhHh3IlQfYvZsgPPlWZjyE6
+SO0JUNgCenuvgawihEHCUvFW/VbeuhxNlcP8w03tXcZCPJd75Xe1GRboa0KEcCwx
+hFMWMZmqLQOZ6XZUAWZIPqKPvBCLJKCDhXwf3kZjX9Geg04+KJwsJt5wJndlWjdb
+LWUIoiy41Jovc3N2hME5cinTllZI4kdOrnZ+NdL5aqoppfjZDQGHESuuPY0vxJEP
+dcfM5Q3BiMo/K/hNCnbp1ywtvbzGqd8/b9OtAgMBAAGjQjBAMB0GA1UdDgQWBBS9
+7L7n9MlfjNgR6RLw5qN+49OOYDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIC5DANBgkqhkiG9w0BAQsFAAOCAgEANnOOVzb6CpOkkXsSwxqaFfrCwJT+L+1O
+H8WvVtewAmzu8TcfuVjwwSgnVMF48TbnA1KvHIWktRNGtSTyEMLN5pH4SvCyK/9w
+IeIOqTNyHmN/4nETT7HjbszdjfsIWYZAjcq2cyhRj+650OJdotUHbBo7iBbAi4TW
+IuqseH4hgrT7qDFebhcVz8ualx9UJkmR7QqWhWqOsMbcLtm4OLZCFNJseaHM/t6H
+seO/OH7FNqe+GMCoXX1m348iJBZ/1ZhBMReqtNMQKpGL23fQqJnUTrD3717kS+xF
+36PsFP5YYtBJ9WMXfX8Wk/YQIimXpcQeuF40VAIw5EG6SxntpBjoSPET2mTj2j9X
+Gunoh3PjYMBOlszrQVs66Qwe+vBj6xdPMHyRI0eTiETnmVG5jUo2cJnr8ztqD6oU
+zCmTX2SXCE9FXJ6MifPHEXJ1OPb9IY5tcUdjxhIB2HAigFHasxBlX44Ob6nHUyJO
+ZqhsF8FouuzSQTRWP7soIA3HT9MlZHhRh3Uef+ZXziKZR/Uyb66uYylIWCWsAoiU
+Hw4wPZhG65XTVQfg7R2cz1w72v7ugXAy3xbGfgLXhFzVnjy/ttIV/TSgpdBquhTQ
+1ZG9Ieiu16avJkphqkmNr/CRCdZqDGp4DGQZNo69POGphapVe7EZenpzDU787oZF
+tugW0JVzMZI=
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/cert-chain-alt.pem b/Istio-Samples/certs/cert-chain-alt.pem
new file mode 100644
index 00000000..204d4090
--- /dev/null
+++ b/Istio-Samples/certs/cert-chain-alt.pem
@@ -0,0 +1,62 @@
+-----BEGIN CERTIFICATE-----
+MIIFeTCCA2GgAwIBAgIUQchu+RczGG1A4BnmrCcpkURQGTAwDQYJKoZIhvcNAQEL
+BQAwIjEOMAwGA1UECgwFSXN0aW8xEDAOBgNVBAMMB1Jvb3QgQ0EwHhcNMjMxMjEx
+MTYyNTI1WhcNMzMxMjA4MTYyNTI1WjA9MQ4wDAYDVQQKDAVJc3RpbzEYMBYGA1UE
+AwwPSW50ZXJtZWRpYXRlIENBMREwDwYDVQQHDAhjbHVzdGVyMTCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAJCkq9Y68g9n0i4xkyYo4mygXIgaj94cvmu3
+X81CLEu/hYrl08acaKZMno+57ibAfxKBsWfA0FMp1eXZ3T9KYlNsSarC8c6RCPbX
+Lzp4iPGMq5n/+OgCGaVUbaLuZB7F6gCJebyM3Du6Zap7X1xm3w2EpiVqHW6iAJqv
+oBNtm7/uzFQiIU3UMeea/XBzo1FpDqNcuc/GgyILs1GA2+U4LfmcwhvUjF36bZ1q
+WMnPfCMHwHTNiGikAJKSXqADz8+rthOyNZq3yFGV/ZOJf6yHOWiyP1BjojRbHCt1
+P8u2nWuD40iqreVrQw3h5Hsz6+mCIkUYFZ45yO0fyRZ/q46M8RKHluD1VI7X6R98
+wB+XPqh12tbXUQJw1/QdtUotszhQq/WUbewX9v4joGIel3MFpoBCoaHh4N4/S1Vk
+9k32c4lEYeV5wO6DZSV9fuasN6KzaiPNNiufP2MnIzJSbal0uZJ0dmyhmHGLGsGc
+t6zxAQpV8reqWZE1mZt94T4TnDpm61BDKRPRu7s6sP42iq6055c+5x3DhVqTInnB
+uTi7oikTykZ2s0budYyjATNMUuz2RHZXxfb6ScqC5mEL0kbKCDgRzS0NS15LHpUX
+Ue65PG8hiuWLuDTcQohWFkeIQyKUGL9uQ5qmmGK8FZwUU/9gY1JjrMw5sa+rVN/C
+hkbRsHmBAgMBAAGjgYswgYgwHQYDVR0OBBYEFP/KjsSWWC+hw1cIaZLn1ZV3IeMq
+MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgLkMCIGA1UdEQQbMBmC
+F2lzdGlvZC5pc3Rpby1zeXN0ZW0uc3ZjMB8GA1UdIwQYMBaAFL3svuf0yV+M2BHp
+EvDmo37j045gMA0GCSqGSIb3DQEBCwUAA4ICAQBO6P+y7UQ7HRyA7dOf2Dvze6xv
+HKgjh8z5uKNbfvmgUT2gECQ+3g0LvDRYHU7w/isSmhCQxIGf+xc7r3+Rtyjg+uEc
+8z0UBysbqrn8pZXPr+FPU5X5czUnwXlZwj02e1fY250LCmfHXFYuPzgwtlbJs2Ec
+2exDG7EZWWX6l/mRFQR8HiF/jum2i06yjO1v+phUVenW/ym2fq+/lY/ZWebQasD7
+7PT3yT/Eage4AIj5zYmZzqJex3OKDiVltAUefnekFJBKqv1UIcWlijRPZPK8uYQk
+IYHRL5fpa9E/HkwY8QopXPJi6Yfx76acY+dQd1xovY3noUVGzQV5wuaICS9V6H9B
+5vkxDYbbABQQ9OJcy8XR7cqlkUATiH5hVRjMSKJiostO+CiVDWjZyJdNgR0kZeaa
+9cSYBdTBxN82A/Vtq4ETq/PG5rR08KQY4HqIlOlo16OxGcJ2zVKSk5lTeI1wx/in
+uOnJTo5mDJHOJrtYGuCLiqZp/Fbcz/Tb9Qccc1yw78feYiNV6JXKx3uPvfsNbXkY
+KnsorT6OQ9G2d/zKPYUw+JEc1BJpk8okvGT8oTfvnfXty63ccN4+iyohQP/GwtQ9
+XiIJ0gGGQjY1VA/L2MOYV0hSMLgddvl4Pt8KXsxQ72gGl8a/s1oOKkYfpm/xchpd
+3ldrrKbAwExwhsARrA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFFDCCAvygAwIBAgIUbQ/RQ9GNnLx7rNVNUJHeizdO1TswDQYJKoZIhvcNAQEL
+BQAwIjEOMAwGA1UECgwFSXN0aW8xEDAOBgNVBAMMB1Jvb3QgQ0EwHhcNMjMxMjEx
+MTYyNDM2WhcNMzMxMjA4MTYyNDM2WjAiMQ4wDAYDVQQKDAVJc3RpbzEQMA4GA1UE
+AwwHUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAN7V2l7b
+/bZsHlWY5qC1p99Au3I0VYr34i/2BIMHSnh1jHn1B6qspjHw2IkqH0SU41M3Vpr7
+m06HGuuZHsq8biUfuUL6Ywt+Vyj2UnPuc6SDPRXxAkBaVGGEAs30akJPkhbbA2qv
+jFxfc2A8GCfnHpGYQkZOvZEQNeHPYkTDsdLEKdbdXkzJMFEGxGDgYiW7xjowDkta
+YlrLBIeHwRCnZ/gTjdCu6oPjCW9JsySbbfx8dYWthIDf/SGqnX8gnDn5K1W5Ip+w
+xaiXZ9FsEzrWd+DXx67sPAS2wl/Qe+RVFLbCGfGnfKdj0CGUtwV/hE2BLWk7fMK/
+dzQR9Bc6GM06uJejZFGuVrwkJldzWW7rp6cJc5D5vJxYCRZZsuk3x6o/mg+z+meh
+kYeUCgsEGU1eKJB7tJ6myiYCLvgjihnnbS0fQlq+9XhHh3IlQfYvZsgPPlWZjyE6
+SO0JUNgCenuvgawihEHCUvFW/VbeuhxNlcP8w03tXcZCPJd75Xe1GRboa0KEcCwx
+hFMWMZmqLQOZ6XZUAWZIPqKPvBCLJKCDhXwf3kZjX9Geg04+KJwsJt5wJndlWjdb
+LWUIoiy41Jovc3N2hME5cinTllZI4kdOrnZ+NdL5aqoppfjZDQGHESuuPY0vxJEP
+dcfM5Q3BiMo/K/hNCnbp1ywtvbzGqd8/b9OtAgMBAAGjQjBAMB0GA1UdDgQWBBS9
+7L7n9MlfjNgR6RLw5qN+49OOYDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIC5DANBgkqhkiG9w0BAQsFAAOCAgEANnOOVzb6CpOkkXsSwxqaFfrCwJT+L+1O
+H8WvVtewAmzu8TcfuVjwwSgnVMF48TbnA1KvHIWktRNGtSTyEMLN5pH4SvCyK/9w
+IeIOqTNyHmN/4nETT7HjbszdjfsIWYZAjcq2cyhRj+650OJdotUHbBo7iBbAi4TW
+IuqseH4hgrT7qDFebhcVz8ualx9UJkmR7QqWhWqOsMbcLtm4OLZCFNJseaHM/t6H
+seO/OH7FNqe+GMCoXX1m348iJBZ/1ZhBMReqtNMQKpGL23fQqJnUTrD3717kS+xF
+36PsFP5YYtBJ9WMXfX8Wk/YQIimXpcQeuF40VAIw5EG6SxntpBjoSPET2mTj2j9X
+Gunoh3PjYMBOlszrQVs66Qwe+vBj6xdPMHyRI0eTiETnmVG5jUo2cJnr8ztqD6oU
+zCmTX2SXCE9FXJ6MifPHEXJ1OPb9IY5tcUdjxhIB2HAigFHasxBlX44Ob6nHUyJO
+ZqhsF8FouuzSQTRWP7soIA3HT9MlZHhRh3Uef+ZXziKZR/Uyb66uYylIWCWsAoiU
+Hw4wPZhG65XTVQfg7R2cz1w72v7ugXAy3xbGfgLXhFzVnjy/ttIV/TSgpdBquhTQ
+1ZG9Ieiu16avJkphqkmNr/CRCdZqDGp4DGQZNo69POGphapVe7EZenpzDU787oZF
+tugW0JVzMZI=
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/cert-chain.pem b/Istio-Samples/certs/cert-chain.pem
new file mode 100644
index 00000000..a460e036
--- /dev/null
+++ b/Istio-Samples/certs/cert-chain.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl
+MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD
+QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx
+OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT
+CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x
+ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9
+iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z
+APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K
+M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom
+ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8
+LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T
+BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC
+AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w
+A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8
+PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y
+05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN
+Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn
+aFKltOc+RAjzDklcUPeG4Y6eMA==
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/generate-workload.sh b/Istio-Samples/certs/generate-workload.sh
new file mode 100755
index 00000000..2ff08c8e
--- /dev/null
+++ b/Istio-Samples/certs/generate-workload.sh
@@ -0,0 +1,111 @@
+#!/bin/bash
+#
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -euo pipefail
+
+name=${1:-foo}
+ns=${2:-$name}
+sa=${3:-$name}
+tmp=${4:-""}
+rootselect=${5:-""}
+san="spiffe://trust-domain-$name/ns/$ns/sa/$sa"
+
+DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+
+FINAL_DIR=$DIR
+if [ -n "$tmp" ]; then
+ if [ -d "$tmp" ]; then
+ FINAL_DIR=$tmp
+ cp "$DIR"/root-cert.pem "$FINAL_DIR"
+ cp "$DIR"/ca-cert.pem "$FINAL_DIR"
+ cp "$DIR"/ca-key.pem "$FINAL_DIR"
+ cp "$DIR"/cert-chain.pem "$FINAL_DIR"
+
+ cp "$DIR"/root-cert-alt.pem "$FINAL_DIR"
+ cp "$DIR"/ca-cert-alt.pem "$FINAL_DIR"
+ cp "$DIR"/ca-key-alt.pem "$FINAL_DIR"
+ cp "$DIR"/cert-chain-alt.pem "$FINAL_DIR"
+
+ else
+ echo "tmp argument is not a directory: $tmp"
+ exit 1
+ fi
+fi
+
+function cleanup() {
+ if [ -f "$FINAL_DIR"/.srl ]; then
+ rm "$FINAL_DIR"/.srl
+ fi
+ if [ -f "$FINAL_DIR"/ca-cert.srl ]; then
+ rm "$FINAL_DIR"/ca-cert.srl
+ fi
+ if [ -f "$FINAL_DIR"/ca-cert-alt.srl ]; then
+ rm "$FINAL_DIR"/ca-cert-alt.srl
+ fi
+ if [ -f "$FINAL_DIR"/workload.cfg ]; then
+ rm "$FINAL_DIR"/workload.cfg
+ fi
+ if [ -f "$FINAL_DIR"/workload.csr ]; then
+ rm "$FINAL_DIR"/workload.csr
+ fi
+}
+
+trap cleanup EXIT
+
+openssl genrsa -out "$FINAL_DIR/workload-$sa-key.pem" 2048
+
+cat > "$FINAL_DIR"/workload.cfg <> "$FINAL_DIR/workload-$sa-cert.pem"
+cp "$certchain" "$FINAL_DIR/workload-$sa-root-certs.pem"
+cat "$rootcert" >> "$FINAL_DIR/workload-$sa-root-certs.pem"
+
+echo "Generated workload-$sa-[cert|key].pem with URI SAN $san"
+openssl verify -CAfile <(cat "$certchain" "$rootcert") "$FINAL_DIR/workload-$sa-cert.pem"
+
diff --git a/Istio-Samples/certs/leaf-workload-bar-cert.pem b/Istio-Samples/certs/leaf-workload-bar-cert.pem
new file mode 100644
index 00000000..b5f4752c
--- /dev/null
+++ b/Istio-Samples/certs/leaf-workload-bar-cert.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIUJS8Ge239oviRxEdt1/drPcAB194wDQYJKoZIhvcNAQEL
+BQAwWTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcT
+CVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8xETAPBgNVBAMTCElzdGlvIENBMB4X
+DTIzMDIwMjE4MjA1MVoXDTMzMDEzMDE4MjA1MVowADCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAOqfOu1GdBXNbvC9iWsqHOWIEQeKTO8UTSYOzflXKQHd
+GCC42TSu+uRRH808Qnyz8Ce6eJJ1UwP+m7S2zZfNbY1L2VJvWboQtFC7egbxp2eR
+91rJ2WmRiQO6ZoAmQG+UVaVMjqWtrOyJ/tkzjXSskZXcbUkWkrPPAkxsSBRWoCXI
+j230dRKggvzZgIgBm4NfDjrdj7AmwEZA0tziPFy/5h+6XJEqD8cFOzKj0Sop80GE
+OzSB8zDnZComFz8CZv2WUkJjngj7rOD+coC1LoWJiUlTFMdAngwSWPsyaqpZtDDw
+Ct+Cs51lhkQQXC6b3t9D9bHbXAxYsEcHaqR+dKVVHIsCAwEAAaN2MHQwDgYDVR0P
+AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB
+Af8EAjAAMDUGA1UdEQEB/wQrMCmGJ3NwaWZmZTovL3RydXN0LWRvbWFpbi1iYXIv
+bnMvYmFyL3NhL2JhcjANBgkqhkiG9w0BAQsFAAOCAQEAjwguC0yf0YavkVJripre
+gVkzLMFSn5MeTxbnHxwDGJAHs+0znOXPrCnAxQ6tU7Z1QwpDLlHEekFKGTLdOz4C
+FT/kDz7ec7SXt2HkPopRSKY+x0FKuxRcYrDTctMliKul5SFU8h3hcT+hIw9ynPU/
+4+I8WxJjpbw91FTddhMCOD2c23xMS9HNENtCxMlR9vrmkKXcim9M0RlPbuMEMbcT
+ntDtdfoHeOC++DdY+41ulGzsbs1NiKdcJu2trxw8axgUFpENo9+xGjmaUdo5AjIE
+JjsPVxRStETMko/pV5i6/hTnE5ZejV/o80OMLXvdIdHVxLO0N0X7fR0xDv45bmY9
+8w==
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/leaf-workload-foo-cert.pem b/Istio-Samples/certs/leaf-workload-foo-cert.pem
new file mode 100644
index 00000000..fee6dcf8
--- /dev/null
+++ b/Istio-Samples/certs/leaf-workload-foo-cert.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIUVrmTEZowmbvjxihqy0tqCb6CDJEwDQYJKoZIhvcNAQEL
+BQAwWTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcT
+CVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8xETAPBgNVBAMTCElzdGlvIENBMB4X
+DTIzMDIwMjE4MjA1N1oXDTMzMDEzMDE4MjA1N1owADCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMRFee8ym0dNiLEaK46r3axHmSaPEu+8weYsq5Jz++pp
+tpLYrRxV79UPKzKqMLmfca1KUs6PYkCipf/hsvNjLwkQf1RRpdScHk17VK/Aa0Er
+3maIDw5TzReqd7MfgsIUStmy6T0WVyzMHVAjDV/aRkTwzWwp29bJgfkvI2/Qy9Mh
+MONNOZ3+m+UcIK4opgg7GmNwynfrPxhWfUsgtYEpaTXEbJOjqQh/8Io56IK4AbS5
+IvNFfN2RKLi0wg9Yzgd+odoifpumaTP6iuJpohSyCgphr8a3jX5DuUNXduveiwMG
++PESc0QSGzAWA11/PWC1v0nU45oWTB31ibduGWenm2cCAwEAAaN2MHQwDgYDVR0P
+AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB
+Af8EAjAAMDUGA1UdEQEB/wQrMCmGJ3NwaWZmZTovL3RydXN0LWRvbWFpbi1mb28v
+bnMvZm9vL3NhL2ZvbzANBgkqhkiG9w0BAQsFAAOCAQEAVwpzfheyDDAitN9zVirV
+WZtk70CMabWPxEMk76/70MK2LBZmC1v1Zhjt9NOj1viTRA8jbi/WtNJhfkdH6UzC
+FaHhPdg8FidIuSazyrXEfiP88L9BLQ2qvJEQq3+ZoyQoCX8bWLOh/8vqm+CgwJR/
+q9JzdYf4rjvXmrm3leHI9Q1AgC83bvNn1FUXBNoMyhHzPYB5/u0j2nlnaeSjc6og
+MSgcq/yrq8CpLK4ZS3E5dk8DQPOlTtACFRCSahRn7O7aqZn3QKZ2dXVzu2Uo0GbE
+Jgkh1hAemPL9zwSxcfz2uBF4J//ecfDM3xccXuBRaXs6qaDwoM1n+84R9VODKLqT
+bw==
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/root-cert-alt.pem b/Istio-Samples/certs/root-cert-alt.pem
new file mode 100644
index 00000000..751429c9
--- /dev/null
+++ b/Istio-Samples/certs/root-cert-alt.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFFDCCAvygAwIBAgIUbQ/RQ9GNnLx7rNVNUJHeizdO1TswDQYJKoZIhvcNAQEL
+BQAwIjEOMAwGA1UECgwFSXN0aW8xEDAOBgNVBAMMB1Jvb3QgQ0EwHhcNMjMxMjEx
+MTYyNDM2WhcNMzMxMjA4MTYyNDM2WjAiMQ4wDAYDVQQKDAVJc3RpbzEQMA4GA1UE
+AwwHUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAN7V2l7b
+/bZsHlWY5qC1p99Au3I0VYr34i/2BIMHSnh1jHn1B6qspjHw2IkqH0SU41M3Vpr7
+m06HGuuZHsq8biUfuUL6Ywt+Vyj2UnPuc6SDPRXxAkBaVGGEAs30akJPkhbbA2qv
+jFxfc2A8GCfnHpGYQkZOvZEQNeHPYkTDsdLEKdbdXkzJMFEGxGDgYiW7xjowDkta
+YlrLBIeHwRCnZ/gTjdCu6oPjCW9JsySbbfx8dYWthIDf/SGqnX8gnDn5K1W5Ip+w
+xaiXZ9FsEzrWd+DXx67sPAS2wl/Qe+RVFLbCGfGnfKdj0CGUtwV/hE2BLWk7fMK/
+dzQR9Bc6GM06uJejZFGuVrwkJldzWW7rp6cJc5D5vJxYCRZZsuk3x6o/mg+z+meh
+kYeUCgsEGU1eKJB7tJ6myiYCLvgjihnnbS0fQlq+9XhHh3IlQfYvZsgPPlWZjyE6
+SO0JUNgCenuvgawihEHCUvFW/VbeuhxNlcP8w03tXcZCPJd75Xe1GRboa0KEcCwx
+hFMWMZmqLQOZ6XZUAWZIPqKPvBCLJKCDhXwf3kZjX9Geg04+KJwsJt5wJndlWjdb
+LWUIoiy41Jovc3N2hME5cinTllZI4kdOrnZ+NdL5aqoppfjZDQGHESuuPY0vxJEP
+dcfM5Q3BiMo/K/hNCnbp1ywtvbzGqd8/b9OtAgMBAAGjQjBAMB0GA1UdDgQWBBS9
+7L7n9MlfjNgR6RLw5qN+49OOYDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIC5DANBgkqhkiG9w0BAQsFAAOCAgEANnOOVzb6CpOkkXsSwxqaFfrCwJT+L+1O
+H8WvVtewAmzu8TcfuVjwwSgnVMF48TbnA1KvHIWktRNGtSTyEMLN5pH4SvCyK/9w
+IeIOqTNyHmN/4nETT7HjbszdjfsIWYZAjcq2cyhRj+650OJdotUHbBo7iBbAi4TW
+IuqseH4hgrT7qDFebhcVz8ualx9UJkmR7QqWhWqOsMbcLtm4OLZCFNJseaHM/t6H
+seO/OH7FNqe+GMCoXX1m348iJBZ/1ZhBMReqtNMQKpGL23fQqJnUTrD3717kS+xF
+36PsFP5YYtBJ9WMXfX8Wk/YQIimXpcQeuF40VAIw5EG6SxntpBjoSPET2mTj2j9X
+Gunoh3PjYMBOlszrQVs66Qwe+vBj6xdPMHyRI0eTiETnmVG5jUo2cJnr8ztqD6oU
+zCmTX2SXCE9FXJ6MifPHEXJ1OPb9IY5tcUdjxhIB2HAigFHasxBlX44Ob6nHUyJO
+ZqhsF8FouuzSQTRWP7soIA3HT9MlZHhRh3Uef+ZXziKZR/Uyb66uYylIWCWsAoiU
+Hw4wPZhG65XTVQfg7R2cz1w72v7ugXAy3xbGfgLXhFzVnjy/ttIV/TSgpdBquhTQ
+1ZG9Ieiu16avJkphqkmNr/CRCdZqDGp4DGQZNo69POGphapVe7EZenpzDU787oZF
+tugW0JVzMZI=
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/root-cert-combined-2.pem b/Istio-Samples/certs/root-cert-combined-2.pem
new file mode 100644
index 00000000..3be5ea66
--- /dev/null
+++ b/Istio-Samples/certs/root-cert-combined-2.pem
@@ -0,0 +1,84 @@
+-----BEGIN CERTIFICATE-----
+MIID7TCCAtWgAwIBAgIJAOIRDhOcxsx6MA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl
+MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD
+QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx
+OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
+DApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTdW5ueXZhbGUxDjAMBgNVBAoMBUlzdGlv
+MQ0wCwYDVQQLDARUZXN0MRAwDgYDVQQDDAdSb290IENBMSIwIAYJKoZIhvcNAQkB
+FhN0ZXN0cm9vdGNhQGlzdGlvLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA38uEfAatzQYqbaLou1nxJ348VyNzumYMmDDt5pbLYRrCo2pS3ki1ZVDN
+8yxIENJFkpKw9UctTGdbNGuGCiSDP7uqF6BiVn+XKAU/3pnPFBbTd0S33NqbDEQu
+IYraHSl/tSk5rARbC1DrQRdZ6nYD2KrapC4g0XbjY6Pu5l4y7KnFwSunnp9uqpZw
+uERv/BgumJ5QlSeSeCmhnDhLxooG8w5tC2yVr1yDpsOHGimP/mc8Cds4V0zfIhQv
+YzfIHphhE9DKjmnjBYLOdj4aycv44jHnOGc+wvA1Jqsl60t3wgms+zJTiWwABLdw
+zgMAa7yxLyoV0+PiVQud6k+8ZoIFcwIDAQABo1AwTjAdBgNVHQ4EFgQUOUYGtUyh
+euxO4lGe4Op1y8NVoagwHwYDVR0jBBgwFoAUOUYGtUyheuxO4lGe4Op1y8NVoagw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANXLyfAs7J9rmBamGJvPZ
+ltx390WxzzLFQsBRAaH6rgeipBq3dR9qEjAwb6BTF+ROmtQzX+fjstCRrJxCto9W
+tC8KvXTdRfIjfCCZjhtIOBKqRxE4KJV/RBfv9xD5lyjtCPCQl3Ia6MSf42N+abAK
+WCdU6KCojA8WB9YhSCzza3aQbPTzd26OC/JblJpVgtus5f8ILzCsz+pbMimgTkhy
+AuhYRppJaQ24APijsEC9+GIaVKPg5IwWroiPoj+QXNpshuvqVQQXvGaRiq4zoSnx
+xAJz+w8tjrDWcf826VN14IL+/Cmqlg/rIfB5CHdwVIfWwpuGB66q/UiPegZMNs8a
+3g==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFFDCCAvygAwIBAgIUbQ/RQ9GNnLx7rNVNUJHeizdO1TswDQYJKoZIhvcNAQEL
+BQAwIjEOMAwGA1UECgwFSXN0aW8xEDAOBgNVBAMMB1Jvb3QgQ0EwHhcNMjMxMjEx
+MTYyNDM2WhcNMzMxMjA4MTYyNDM2WjAiMQ4wDAYDVQQKDAVJc3RpbzEQMA4GA1UE
+AwwHUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAN7V2l7b
+/bZsHlWY5qC1p99Au3I0VYr34i/2BIMHSnh1jHn1B6qspjHw2IkqH0SU41M3Vpr7
+m06HGuuZHsq8biUfuUL6Ywt+Vyj2UnPuc6SDPRXxAkBaVGGEAs30akJPkhbbA2qv
+jFxfc2A8GCfnHpGYQkZOvZEQNeHPYkTDsdLEKdbdXkzJMFEGxGDgYiW7xjowDkta
+YlrLBIeHwRCnZ/gTjdCu6oPjCW9JsySbbfx8dYWthIDf/SGqnX8gnDn5K1W5Ip+w
+xaiXZ9FsEzrWd+DXx67sPAS2wl/Qe+RVFLbCGfGnfKdj0CGUtwV/hE2BLWk7fMK/
+dzQR9Bc6GM06uJejZFGuVrwkJldzWW7rp6cJc5D5vJxYCRZZsuk3x6o/mg+z+meh
+kYeUCgsEGU1eKJB7tJ6myiYCLvgjihnnbS0fQlq+9XhHh3IlQfYvZsgPPlWZjyE6
+SO0JUNgCenuvgawihEHCUvFW/VbeuhxNlcP8w03tXcZCPJd75Xe1GRboa0KEcCwx
+hFMWMZmqLQOZ6XZUAWZIPqKPvBCLJKCDhXwf3kZjX9Geg04+KJwsJt5wJndlWjdb
+LWUIoiy41Jovc3N2hME5cinTllZI4kdOrnZ+NdL5aqoppfjZDQGHESuuPY0vxJEP
+dcfM5Q3BiMo/K/hNCnbp1ywtvbzGqd8/b9OtAgMBAAGjQjBAMB0GA1UdDgQWBBS9
+7L7n9MlfjNgR6RLw5qN+49OOYDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIC5DANBgkqhkiG9w0BAQsFAAOCAgEANnOOVzb6CpOkkXsSwxqaFfrCwJT+L+1O
+H8WvVtewAmzu8TcfuVjwwSgnVMF48TbnA1KvHIWktRNGtSTyEMLN5pH4SvCyK/9w
+IeIOqTNyHmN/4nETT7HjbszdjfsIWYZAjcq2cyhRj+650OJdotUHbBo7iBbAi4TW
+IuqseH4hgrT7qDFebhcVz8ualx9UJkmR7QqWhWqOsMbcLtm4OLZCFNJseaHM/t6H
+seO/OH7FNqe+GMCoXX1m348iJBZ/1ZhBMReqtNMQKpGL23fQqJnUTrD3717kS+xF
+36PsFP5YYtBJ9WMXfX8Wk/YQIimXpcQeuF40VAIw5EG6SxntpBjoSPET2mTj2j9X
+Gunoh3PjYMBOlszrQVs66Qwe+vBj6xdPMHyRI0eTiETnmVG5jUo2cJnr8ztqD6oU
+zCmTX2SXCE9FXJ6MifPHEXJ1OPb9IY5tcUdjxhIB2HAigFHasxBlX44Ob6nHUyJO
+ZqhsF8FouuzSQTRWP7soIA3HT9MlZHhRh3Uef+ZXziKZR/Uyb66uYylIWCWsAoiU
+Hw4wPZhG65XTVQfg7R2cz1w72v7ugXAy3xbGfgLXhFzVnjy/ttIV/TSgpdBquhTQ
+1ZG9Ieiu16avJkphqkmNr/CRCdZqDGp4DGQZNo69POGphapVe7EZenpzDU787oZF
+tugW0JVzMZI=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFFDCCAvygAwIBAgIUbQ/RQ9GNnLx7rNVNUJHeizdO1TswDQYJKoZIhvcNAQEL
+BQAwIjEOMAwGA1UECgwFSXN0aW8xEDAOBgNVBAMMB1Jvb3QgQ0EwHhcNMjMxMjEx
+MTYyNDM2WhcNMzMxMjA4MTYyNDM2WjAiMQ4wDAYDVQQKDAVJc3RpbzEQMA4GA1UE
+AwwHUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAN7V2l7b
+/bZsHlWY5qC1p99Au3I0VYr34i/2BIMHSnh1jHn1B6qspjHw2IkqH0SU41M3Vpr7
+m06HGuuZHsq8biUfuUL6Ywt+Vyj2UnPuc6SDPRXxAkBaVGGEAs30akJPkhbbA2qv
+jFxfc2A8GCfnHpGYQkZOvZEQNeHPYkTDsdLEKdbdXkzJMFEGxGDgYiW7xjowDkta
+YlrLBIeHwRCnZ/gTjdCu6oPjCW9JsySbbfx8dYWthIDf/SGqnX8gnDn5K1W5Ip+w
+xaiXZ9FsEzrWd+DXx67sPAS2wl/Qe+RVFLbCGfGnfKdj0CGUtwV/hE2BLWk7fMK/
+dzQR9Bc6GM06uJejZFGuVrwkJldzWW7rp6cJc5D5vJxYCRZZsuk3x6o/mg+z+meh
+kYeUCgsEGU1eKJB7tJ6myiYCLvgjihnnbS0fQlq+9XhHh3IlQfYvZsgPPlWZjyE6
+SO0JUNgCenuvgawihEHCUvFW/VbeuhxNlcP8w03tXcZCPJd75Xe1GRboa0KEcCwx
+hFMWMZmqLQOZ6XZUAWZIPqKPvBCLJKCDhXwf3kZjX9Geg04+KJwsJt5wJndlWjdb
+LWUIoiy41Jovc3N2hME5cinTllZI4kdOrnZ+NdL5aqoppfjZDQGHESuuPY0vxJEP
+dcfM5Q3BiMo/K/hNCnbp1ywtvbzGqd8/b9OtAgMBAAGjQjBAMB0GA1UdDgQWBBS9
+7L7n9MlfjNgR6RLw5qN+49OOYDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIC5DANBgkqhkiG9w0BAQsFAAOCAgEANnOOVzb6CpOkkXsSwxqaFfrCwJT+L+1O
+H8WvVtewAmzu8TcfuVjwwSgnVMF48TbnA1KvHIWktRNGtSTyEMLN5pH4SvCyK/9w
+IeIOqTNyHmN/4nETT7HjbszdjfsIWYZAjcq2cyhRj+650OJdotUHbBo7iBbAi4TW
+IuqseH4hgrT7qDFebhcVz8ualx9UJkmR7QqWhWqOsMbcLtm4OLZCFNJseaHM/t6H
+seO/OH7FNqe+GMCoXX1m348iJBZ/1ZhBMReqtNMQKpGL23fQqJnUTrD3717kS+xF
+36PsFP5YYtBJ9WMXfX8Wk/YQIimXpcQeuF40VAIw5EG6SxntpBjoSPET2mTj2j9X
+Gunoh3PjYMBOlszrQVs66Qwe+vBj6xdPMHyRI0eTiETnmVG5jUo2cJnr8ztqD6oU
+zCmTX2SXCE9FXJ6MifPHEXJ1OPb9IY5tcUdjxhIB2HAigFHasxBlX44Ob6nHUyJO
+ZqhsF8FouuzSQTRWP7soIA3HT9MlZHhRh3Uef+ZXziKZR/Uyb66uYylIWCWsAoiU
+Hw4wPZhG65XTVQfg7R2cz1w72v7ugXAy3xbGfgLXhFzVnjy/ttIV/TSgpdBquhTQ
+1ZG9Ieiu16avJkphqkmNr/CRCdZqDGp4DGQZNo69POGphapVe7EZenpzDU787oZF
+tugW0JVzMZI=
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/Istio-Samples/certs/root-cert-combined.pem b/Istio-Samples/certs/root-cert-combined.pem
new file mode 100644
index 00000000..fc7ee45a
--- /dev/null
+++ b/Istio-Samples/certs/root-cert-combined.pem
@@ -0,0 +1,54 @@
+-----BEGIN CERTIFICATE-----
+MIID7TCCAtWgAwIBAgIJAOIRDhOcxsx6MA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl
+MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD
+QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx
+OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
+DApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTdW5ueXZhbGUxDjAMBgNVBAoMBUlzdGlv
+MQ0wCwYDVQQLDARUZXN0MRAwDgYDVQQDDAdSb290IENBMSIwIAYJKoZIhvcNAQkB
+FhN0ZXN0cm9vdGNhQGlzdGlvLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA38uEfAatzQYqbaLou1nxJ348VyNzumYMmDDt5pbLYRrCo2pS3ki1ZVDN
+8yxIENJFkpKw9UctTGdbNGuGCiSDP7uqF6BiVn+XKAU/3pnPFBbTd0S33NqbDEQu
+IYraHSl/tSk5rARbC1DrQRdZ6nYD2KrapC4g0XbjY6Pu5l4y7KnFwSunnp9uqpZw
+uERv/BgumJ5QlSeSeCmhnDhLxooG8w5tC2yVr1yDpsOHGimP/mc8Cds4V0zfIhQv
+YzfIHphhE9DKjmnjBYLOdj4aycv44jHnOGc+wvA1Jqsl60t3wgms+zJTiWwABLdw
+zgMAa7yxLyoV0+PiVQud6k+8ZoIFcwIDAQABo1AwTjAdBgNVHQ4EFgQUOUYGtUyh
+euxO4lGe4Op1y8NVoagwHwYDVR0jBBgwFoAUOUYGtUyheuxO4lGe4Op1y8NVoagw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANXLyfAs7J9rmBamGJvPZ
+ltx390WxzzLFQsBRAaH6rgeipBq3dR9qEjAwb6BTF+ROmtQzX+fjstCRrJxCto9W
+tC8KvXTdRfIjfCCZjhtIOBKqRxE4KJV/RBfv9xD5lyjtCPCQl3Ia6MSf42N+abAK
+WCdU6KCojA8WB9YhSCzza3aQbPTzd26OC/JblJpVgtus5f8ILzCsz+pbMimgTkhy
+AuhYRppJaQ24APijsEC9+GIaVKPg5IwWroiPoj+QXNpshuvqVQQXvGaRiq4zoSnx
+xAJz+w8tjrDWcf826VN14IL+/Cmqlg/rIfB5CHdwVIfWwpuGB66q/UiPegZMNs8a
+3g==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFFDCCAvygAwIBAgIUbQ/RQ9GNnLx7rNVNUJHeizdO1TswDQYJKoZIhvcNAQEL
+BQAwIjEOMAwGA1UECgwFSXN0aW8xEDAOBgNVBAMMB1Jvb3QgQ0EwHhcNMjMxMjEx
+MTYyNDM2WhcNMzMxMjA4MTYyNDM2WjAiMQ4wDAYDVQQKDAVJc3RpbzEQMA4GA1UE
+AwwHUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAN7V2l7b
+/bZsHlWY5qC1p99Au3I0VYr34i/2BIMHSnh1jHn1B6qspjHw2IkqH0SU41M3Vpr7
+m06HGuuZHsq8biUfuUL6Ywt+Vyj2UnPuc6SDPRXxAkBaVGGEAs30akJPkhbbA2qv
+jFxfc2A8GCfnHpGYQkZOvZEQNeHPYkTDsdLEKdbdXkzJMFEGxGDgYiW7xjowDkta
+YlrLBIeHwRCnZ/gTjdCu6oPjCW9JsySbbfx8dYWthIDf/SGqnX8gnDn5K1W5Ip+w
+xaiXZ9FsEzrWd+DXx67sPAS2wl/Qe+RVFLbCGfGnfKdj0CGUtwV/hE2BLWk7fMK/
+dzQR9Bc6GM06uJejZFGuVrwkJldzWW7rp6cJc5D5vJxYCRZZsuk3x6o/mg+z+meh
+kYeUCgsEGU1eKJB7tJ6myiYCLvgjihnnbS0fQlq+9XhHh3IlQfYvZsgPPlWZjyE6
+SO0JUNgCenuvgawihEHCUvFW/VbeuhxNlcP8w03tXcZCPJd75Xe1GRboa0KEcCwx
+hFMWMZmqLQOZ6XZUAWZIPqKPvBCLJKCDhXwf3kZjX9Geg04+KJwsJt5wJndlWjdb
+LWUIoiy41Jovc3N2hME5cinTllZI4kdOrnZ+NdL5aqoppfjZDQGHESuuPY0vxJEP
+dcfM5Q3BiMo/K/hNCnbp1ywtvbzGqd8/b9OtAgMBAAGjQjBAMB0GA1UdDgQWBBS9
+7L7n9MlfjNgR6RLw5qN+49OOYDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIC5DANBgkqhkiG9w0BAQsFAAOCAgEANnOOVzb6CpOkkXsSwxqaFfrCwJT+L+1O
+H8WvVtewAmzu8TcfuVjwwSgnVMF48TbnA1KvHIWktRNGtSTyEMLN5pH4SvCyK/9w
+IeIOqTNyHmN/4nETT7HjbszdjfsIWYZAjcq2cyhRj+650OJdotUHbBo7iBbAi4TW
+IuqseH4hgrT7qDFebhcVz8ualx9UJkmR7QqWhWqOsMbcLtm4OLZCFNJseaHM/t6H
+seO/OH7FNqe+GMCoXX1m348iJBZ/1ZhBMReqtNMQKpGL23fQqJnUTrD3717kS+xF
+36PsFP5YYtBJ9WMXfX8Wk/YQIimXpcQeuF40VAIw5EG6SxntpBjoSPET2mTj2j9X
+Gunoh3PjYMBOlszrQVs66Qwe+vBj6xdPMHyRI0eTiETnmVG5jUo2cJnr8ztqD6oU
+zCmTX2SXCE9FXJ6MifPHEXJ1OPb9IY5tcUdjxhIB2HAigFHasxBlX44Ob6nHUyJO
+ZqhsF8FouuzSQTRWP7soIA3HT9MlZHhRh3Uef+ZXziKZR/Uyb66uYylIWCWsAoiU
+Hw4wPZhG65XTVQfg7R2cz1w72v7ugXAy3xbGfgLXhFzVnjy/ttIV/TSgpdBquhTQ
+1ZG9Ieiu16avJkphqkmNr/CRCdZqDGp4DGQZNo69POGphapVe7EZenpzDU787oZF
+tugW0JVzMZI=
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/Istio-Samples/certs/root-cert.pem b/Istio-Samples/certs/root-cert.pem
new file mode 100644
index 00000000..64c3fd50
--- /dev/null
+++ b/Istio-Samples/certs/root-cert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID7TCCAtWgAwIBAgIJAOIRDhOcxsx6MA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl
+MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD
+QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx
+OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
+DApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTdW5ueXZhbGUxDjAMBgNVBAoMBUlzdGlv
+MQ0wCwYDVQQLDARUZXN0MRAwDgYDVQQDDAdSb290IENBMSIwIAYJKoZIhvcNAQkB
+FhN0ZXN0cm9vdGNhQGlzdGlvLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA38uEfAatzQYqbaLou1nxJ348VyNzumYMmDDt5pbLYRrCo2pS3ki1ZVDN
+8yxIENJFkpKw9UctTGdbNGuGCiSDP7uqF6BiVn+XKAU/3pnPFBbTd0S33NqbDEQu
+IYraHSl/tSk5rARbC1DrQRdZ6nYD2KrapC4g0XbjY6Pu5l4y7KnFwSunnp9uqpZw
+uERv/BgumJ5QlSeSeCmhnDhLxooG8w5tC2yVr1yDpsOHGimP/mc8Cds4V0zfIhQv
+YzfIHphhE9DKjmnjBYLOdj4aycv44jHnOGc+wvA1Jqsl60t3wgms+zJTiWwABLdw
+zgMAa7yxLyoV0+PiVQud6k+8ZoIFcwIDAQABo1AwTjAdBgNVHQ4EFgQUOUYGtUyh
+euxO4lGe4Op1y8NVoagwHwYDVR0jBBgwFoAUOUYGtUyheuxO4lGe4Op1y8NVoagw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANXLyfAs7J9rmBamGJvPZ
+ltx390WxzzLFQsBRAaH6rgeipBq3dR9qEjAwb6BTF+ROmtQzX+fjstCRrJxCto9W
+tC8KvXTdRfIjfCCZjhtIOBKqRxE4KJV/RBfv9xD5lyjtCPCQl3Ia6MSf42N+abAK
+WCdU6KCojA8WB9YhSCzza3aQbPTzd26OC/JblJpVgtus5f8ILzCsz+pbMimgTkhy
+AuhYRppJaQ24APijsEC9+GIaVKPg5IwWroiPoj+QXNpshuvqVQQXvGaRiq4zoSnx
+xAJz+w8tjrDWcf826VN14IL+/Cmqlg/rIfB5CHdwVIfWwpuGB66q/UiPegZMNs8a
+3g==
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/workload-bar-cert.pem b/Istio-Samples/certs/workload-bar-cert.pem
new file mode 100644
index 00000000..1b59e9c5
--- /dev/null
+++ b/Istio-Samples/certs/workload-bar-cert.pem
@@ -0,0 +1,43 @@
+-----BEGIN CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIUJS8Ge239oviRxEdt1/drPcAB194wDQYJKoZIhvcNAQEL
+BQAwWTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcT
+CVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8xETAPBgNVBAMTCElzdGlvIENBMB4X
+DTIzMDIwMjE4MjA1MVoXDTMzMDEzMDE4MjA1MVowADCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAOqfOu1GdBXNbvC9iWsqHOWIEQeKTO8UTSYOzflXKQHd
+GCC42TSu+uRRH808Qnyz8Ce6eJJ1UwP+m7S2zZfNbY1L2VJvWboQtFC7egbxp2eR
+91rJ2WmRiQO6ZoAmQG+UVaVMjqWtrOyJ/tkzjXSskZXcbUkWkrPPAkxsSBRWoCXI
+j230dRKggvzZgIgBm4NfDjrdj7AmwEZA0tziPFy/5h+6XJEqD8cFOzKj0Sop80GE
+OzSB8zDnZComFz8CZv2WUkJjngj7rOD+coC1LoWJiUlTFMdAngwSWPsyaqpZtDDw
+Ct+Cs51lhkQQXC6b3t9D9bHbXAxYsEcHaqR+dKVVHIsCAwEAAaN2MHQwDgYDVR0P
+AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB
+Af8EAjAAMDUGA1UdEQEB/wQrMCmGJ3NwaWZmZTovL3RydXN0LWRvbWFpbi1iYXIv
+bnMvYmFyL3NhL2JhcjANBgkqhkiG9w0BAQsFAAOCAQEAjwguC0yf0YavkVJripre
+gVkzLMFSn5MeTxbnHxwDGJAHs+0znOXPrCnAxQ6tU7Z1QwpDLlHEekFKGTLdOz4C
+FT/kDz7ec7SXt2HkPopRSKY+x0FKuxRcYrDTctMliKul5SFU8h3hcT+hIw9ynPU/
+4+I8WxJjpbw91FTddhMCOD2c23xMS9HNENtCxMlR9vrmkKXcim9M0RlPbuMEMbcT
+ntDtdfoHeOC++DdY+41ulGzsbs1NiKdcJu2trxw8axgUFpENo9+xGjmaUdo5AjIE
+JjsPVxRStETMko/pV5i6/hTnE5ZejV/o80OMLXvdIdHVxLO0N0X7fR0xDv45bmY9
+8w==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl
+MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD
+QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx
+OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT
+CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x
+ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9
+iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z
+APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K
+M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom
+ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8
+LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T
+BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC
+AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w
+A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8
+PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y
+05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN
+Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn
+aFKltOc+RAjzDklcUPeG4Y6eMA==
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/workload-bar-key.pem b/Istio-Samples/certs/workload-bar-key.pem
new file mode 100644
index 00000000..1b7889a9
--- /dev/null
+++ b/Istio-Samples/certs/workload-bar-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA6p867UZ0Fc1u8L2Jayoc5YgRB4pM7xRNJg7N+VcpAd0YILjZ
+NK765FEfzTxCfLPwJ7p4knVTA/6btLbNl81tjUvZUm9ZuhC0ULt6BvGnZ5H3WsnZ
+aZGJA7pmgCZAb5RVpUyOpa2s7In+2TONdKyRldxtSRaSs88CTGxIFFagJciPbfR1
+EqCC/NmAiAGbg18OOt2PsCbARkDS3OI8XL/mH7pckSoPxwU7MqPRKinzQYQ7NIHz
+MOdkKiYXPwJm/ZZSQmOeCPus4P5ygLUuhYmJSVMUx0CeDBJY+zJqqlm0MPAK34Kz
+nWWGRBBcLpve30P1sdtcDFiwRwdqpH50pVUciwIDAQABAoIBABVjCmYSpAZQwaok
+POCN6DBsJNFBJB4vBZFQjCoMbeqDku14rCQHR0uEsZdtxMnFRUD52H/RPg4BKYRh
+nYAW88OLhHXlPJKfbzBkxozXfmEMhzW5bJ4Y7Bpw5WMNGZaSOPRmdCJaIIc3VQnL
+jztxd5vnifa9ngXR+u2oeTGRa+vFncwtf+lDjid6KOsclFEOVRquT9e3BgccwWJL
+O7k8GZzHCWj+jxeExrcoD5NMulHZGDTc49ZZeqpVIwQnhFEe+e6LcZ7jaHs1AgUK
+v3cHVQUoeHa+NYATeoyXWUJzD0vW6fTgxUrf+GNrtdmbwaoGW4+FmsYKB0YD2FO3
+bQ5cQWECgYEA+sXSllaDmrwFhX7Tga7nHN74maGk0V4eUnVQ2rkwRXgwaUh+V3K7
+5jJ1ZTZuWYbAWup+rVt0cAb0Ja8zBnnkHRdwe0gQqtoj+5YdD8RAluBJePFigp77
+pK+JfdiYnA0JC3Z+7gkeWM/uY9ojDuasX83yVf7Kgm+7HMUrh5dGaDMCgYEA74M5
+Q32oM8zxGm9ck82rh7ox0NwTeIrwr5U42QFqT0h26nR3m51l8odj3rz0WnRtOfAl
+sjJ3y5tygdVLMzwpuHzpA/iq7YRY04+g7Q5MoVAImLKzKJzIxZra+6eo2ctcQCBO
+U90+jY4C4/YgvTYKnndFvlVXcXXNyhPJKlfLAkkCgYEA8yOWmHjtRLuERvi+rYAd
+SJrPQnW9TdoJYD2q1Ua0jMaJear2BGeT0w+dTzLFLzw9iGjPxdlkPbIgSeFigabx
+C1vMjVtD/cNfG/Fh4AWR8jcoRYEU2Dy5E+W2UzQMU1E4McsEKlrg948zPdEkKLBy
+9LjDe6l8Q5d9PdnV6LM9ao0CgYAnY7NVMCMrcbbtHAdjn11oUuzCZo8lMeRnW+kf
+dyYep9I2uLS6+OW9PxrjlLuy7JbSAnaQmdAtwgDQ7V0SrgBGgPRpXMnvieZ51JMo
+qUNc/CaNxkXElhRGuzLsVCRmvRUMzsNS833IFeTPzLiRpYOVkBP+O1bIKBGR/DMH
+La0LUQKBgQD0Jea309Qr3CZIDp8IYnthYHIezDPmRBbyMKK5kTj/GC19JIXJoonw
+nUw9vpVp+WdBy+ZP/567eUp9RrG9xP+OrirWeUT8UFdmpc+JbI54b2tX0UgUePKm
+oKXf/DlOM5K2gDaIL+wlFYuxdrLtFCxvFP+7ihueivunjbtENQqdGA==
+-----END RSA PRIVATE KEY-----
diff --git a/Istio-Samples/certs/workload-bar-root-certs.pem b/Istio-Samples/certs/workload-bar-root-certs.pem
new file mode 100644
index 00000000..9a43073e
--- /dev/null
+++ b/Istio-Samples/certs/workload-bar-root-certs.pem
@@ -0,0 +1,46 @@
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl
+MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD
+QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx
+OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT
+CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x
+ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9
+iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z
+APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K
+M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom
+ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8
+LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T
+BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC
+AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w
+A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8
+PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y
+05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN
+Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn
+aFKltOc+RAjzDklcUPeG4Y6eMA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID7TCCAtWgAwIBAgIJAOIRDhOcxsx6MA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl
+MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD
+QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx
+OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
+DApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTdW5ueXZhbGUxDjAMBgNVBAoMBUlzdGlv
+MQ0wCwYDVQQLDARUZXN0MRAwDgYDVQQDDAdSb290IENBMSIwIAYJKoZIhvcNAQkB
+FhN0ZXN0cm9vdGNhQGlzdGlvLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA38uEfAatzQYqbaLou1nxJ348VyNzumYMmDDt5pbLYRrCo2pS3ki1ZVDN
+8yxIENJFkpKw9UctTGdbNGuGCiSDP7uqF6BiVn+XKAU/3pnPFBbTd0S33NqbDEQu
+IYraHSl/tSk5rARbC1DrQRdZ6nYD2KrapC4g0XbjY6Pu5l4y7KnFwSunnp9uqpZw
+uERv/BgumJ5QlSeSeCmhnDhLxooG8w5tC2yVr1yDpsOHGimP/mc8Cds4V0zfIhQv
+YzfIHphhE9DKjmnjBYLOdj4aycv44jHnOGc+wvA1Jqsl60t3wgms+zJTiWwABLdw
+zgMAa7yxLyoV0+PiVQud6k+8ZoIFcwIDAQABo1AwTjAdBgNVHQ4EFgQUOUYGtUyh
+euxO4lGe4Op1y8NVoagwHwYDVR0jBBgwFoAUOUYGtUyheuxO4lGe4Op1y8NVoagw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANXLyfAs7J9rmBamGJvPZ
+ltx390WxzzLFQsBRAaH6rgeipBq3dR9qEjAwb6BTF+ROmtQzX+fjstCRrJxCto9W
+tC8KvXTdRfIjfCCZjhtIOBKqRxE4KJV/RBfv9xD5lyjtCPCQl3Ia6MSf42N+abAK
+WCdU6KCojA8WB9YhSCzza3aQbPTzd26OC/JblJpVgtus5f8ILzCsz+pbMimgTkhy
+AuhYRppJaQ24APijsEC9+GIaVKPg5IwWroiPoj+QXNpshuvqVQQXvGaRiq4zoSnx
+xAJz+w8tjrDWcf826VN14IL+/Cmqlg/rIfB5CHdwVIfWwpuGB66q/UiPegZMNs8a
+3g==
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/workload-foo-cert.pem b/Istio-Samples/certs/workload-foo-cert.pem
new file mode 100644
index 00000000..50197b98
--- /dev/null
+++ b/Istio-Samples/certs/workload-foo-cert.pem
@@ -0,0 +1,43 @@
+-----BEGIN CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIUVrmTEZowmbvjxihqy0tqCb6CDJEwDQYJKoZIhvcNAQEL
+BQAwWTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcT
+CVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8xETAPBgNVBAMTCElzdGlvIENBMB4X
+DTIzMDIwMjE4MjA1N1oXDTMzMDEzMDE4MjA1N1owADCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMRFee8ym0dNiLEaK46r3axHmSaPEu+8weYsq5Jz++pp
+tpLYrRxV79UPKzKqMLmfca1KUs6PYkCipf/hsvNjLwkQf1RRpdScHk17VK/Aa0Er
+3maIDw5TzReqd7MfgsIUStmy6T0WVyzMHVAjDV/aRkTwzWwp29bJgfkvI2/Qy9Mh
+MONNOZ3+m+UcIK4opgg7GmNwynfrPxhWfUsgtYEpaTXEbJOjqQh/8Io56IK4AbS5
+IvNFfN2RKLi0wg9Yzgd+odoifpumaTP6iuJpohSyCgphr8a3jX5DuUNXduveiwMG
++PESc0QSGzAWA11/PWC1v0nU45oWTB31ibduGWenm2cCAwEAAaN2MHQwDgYDVR0P
+AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB
+Af8EAjAAMDUGA1UdEQEB/wQrMCmGJ3NwaWZmZTovL3RydXN0LWRvbWFpbi1mb28v
+bnMvZm9vL3NhL2ZvbzANBgkqhkiG9w0BAQsFAAOCAQEAVwpzfheyDDAitN9zVirV
+WZtk70CMabWPxEMk76/70MK2LBZmC1v1Zhjt9NOj1viTRA8jbi/WtNJhfkdH6UzC
+FaHhPdg8FidIuSazyrXEfiP88L9BLQ2qvJEQq3+ZoyQoCX8bWLOh/8vqm+CgwJR/
+q9JzdYf4rjvXmrm3leHI9Q1AgC83bvNn1FUXBNoMyhHzPYB5/u0j2nlnaeSjc6og
+MSgcq/yrq8CpLK4ZS3E5dk8DQPOlTtACFRCSahRn7O7aqZn3QKZ2dXVzu2Uo0GbE
+Jgkh1hAemPL9zwSxcfz2uBF4J//ecfDM3xccXuBRaXs6qaDwoM1n+84R9VODKLqT
+bw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl
+MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD
+QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx
+OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT
+CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x
+ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9
+iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z
+APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K
+M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom
+ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8
+LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T
+BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC
+AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w
+A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8
+PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y
+05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN
+Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn
+aFKltOc+RAjzDklcUPeG4Y6eMA==
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/certs/workload-foo-key.pem b/Istio-Samples/certs/workload-foo-key.pem
new file mode 100644
index 00000000..bac90f1e
--- /dev/null
+++ b/Istio-Samples/certs/workload-foo-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpgIBAAKCAQEAxEV57zKbR02IsRorjqvdrEeZJo8S77zB5iyrknP76mm2ktit
+HFXv1Q8rMqowuZ9xrUpSzo9iQKKl/+Gy82MvCRB/VFGl1JweTXtUr8BrQSveZogP
+DlPNF6p3sx+CwhRK2bLpPRZXLMwdUCMNX9pGRPDNbCnb1smB+S8jb9DL0yEw4005
+nf6b5RwgriimCDsaY3DKd+s/GFZ9SyC1gSlpNcRsk6OpCH/wijnogrgBtLki80V8
+3ZEouLTCD1jOB36h2iJ+m6ZpM/qK4mmiFLIKCmGvxreNfkO5Q1d2696LAwb48RJz
+RBIbMBYDXX89YLW/SdTjmhZMHfWJt24ZZ6ebZwIDAQABAoIBAQC+W0vZrFFhpFcw
+vVsFcrb6Qi7NcPJCxeWhIi39SrRHM+Q5JCExXD/RenbBGsNLJNMR6QXLBNGcMqOh
+OvtehxG1TuTPmKinPgs9xqHqG0tq1+tJsig4ExrVGyYg+izNovS9k4IXFzXRYt4D
+PRvZnU+NyabSgv6OoL2IOim6Zt1olBIHK0u57bNEFLoLJBHi+/qxVo1H1ZxW4eg/
+/hCkg8IlT7G1wrT9uwAU5ld6wpG6OYub4uHLPsoyWB4E2vl1/liZq4MnUJG0M5m5
+QWHy9wL3jow/LtjVvcn/I09YIJKI9BocUi6/ze/Boy1zo4cL+cryLpfplIhZ0u/N
+a/S/222BAoGBAPPXTLJyfSEt70+H2iYPKEBMVo8UBAW2rSICOCMvKZJuCuqccB75
+Jy6h+BQtIJZf+rnNzlG4EH6Vjb4mC/YYBf0U1inpCsdKcw96hv7+EYzBtKf/lK9N
+au+AEAgngr1xgA+M84jMWnosFMNw88pO6j260y1aMUmLD8onrnglPcEHAoGBAM4O
+79WMqTXipgvQzx66KeQQs6Gf1nwh4Ut9NYs2nk4KQrkAHd4zuURFlxdnqr/mC4wb
+nsLCdFOOZaiWIIG93lp0Ox0dLar2jJK88WfCzzerUBljMRv8xJZBLOe7rv5iawVC
+mBnZE606m1kTrj6wY5M7TsZiIIeYQcmlJNmW9ZqhAoGBAMY+iqqiDj2FfQTp7F/4
+/r6X0d/tY//JLyVxLHbehyv3r4Riv31PD54ILQsqTU40pkGdo1opDa/8owqvIBZq
+HaRO5neYchzo2HcDJPH3WglYCypyzk1f4crqER6wEMk4l+cMr4rOqdieMhtbn7kh
+Q6wAUmSS6XNjTekLLfucO4LNAoGBAIjIgYxQg0Kx4WeWhObwzT4HmDaB0+8yzks+
+Inz3FL7ZMNF9slX+H82iJFn1BvO70Y6ABzNhwbZ1oCX5Ajsdvqxs25DH/bivUUFX
+CyjFuKhLoDA6GC9r61OSkCyD+fYDfudO/YirANTNQrIuzkvu6yqhA/nMyas49vLU
+HVITU5YBAoGBANJVeCLwpjoK2ROM6mIQrHtBR5Ft0a5DhjQWT/6FrsUXGYH3nsdt
+cEUCJsBU7z46GcByRIT25xGimoitQppsw6Wcf0gtjNyqbF56aejjEkd5LNtm77gz
+9wNya77NzyrtiAjG9TCnDPJUX7satEoXgEGMxmtoiQ+pbD3nvJsFjkZQ
+-----END RSA PRIVATE KEY-----
diff --git a/Istio-Samples/certs/workload-foo-root-certs.pem b/Istio-Samples/certs/workload-foo-root-certs.pem
new file mode 100644
index 00000000..9a43073e
--- /dev/null
+++ b/Istio-Samples/certs/workload-foo-root-certs.pem
@@ -0,0 +1,46 @@
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl
+MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD
+QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx
+OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT
+CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x
+ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9
+iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z
+APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K
+M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom
+ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8
+LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T
+BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC
+AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w
+A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8
+PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y
+05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN
+Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn
+aFKltOc+RAjzDklcUPeG4Y6eMA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID7TCCAtWgAwIBAgIJAOIRDhOcxsx6MA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl
+MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD
+QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx
+OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
+DApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTdW5ueXZhbGUxDjAMBgNVBAoMBUlzdGlv
+MQ0wCwYDVQQLDARUZXN0MRAwDgYDVQQDDAdSb290IENBMSIwIAYJKoZIhvcNAQkB
+FhN0ZXN0cm9vdGNhQGlzdGlvLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA38uEfAatzQYqbaLou1nxJ348VyNzumYMmDDt5pbLYRrCo2pS3ki1ZVDN
+8yxIENJFkpKw9UctTGdbNGuGCiSDP7uqF6BiVn+XKAU/3pnPFBbTd0S33NqbDEQu
+IYraHSl/tSk5rARbC1DrQRdZ6nYD2KrapC4g0XbjY6Pu5l4y7KnFwSunnp9uqpZw
+uERv/BgumJ5QlSeSeCmhnDhLxooG8w5tC2yVr1yDpsOHGimP/mc8Cds4V0zfIhQv
+YzfIHphhE9DKjmnjBYLOdj4aycv44jHnOGc+wvA1Jqsl60t3wgms+zJTiWwABLdw
+zgMAa7yxLyoV0+PiVQud6k+8ZoIFcwIDAQABo1AwTjAdBgNVHQ4EFgQUOUYGtUyh
+euxO4lGe4Op1y8NVoagwHwYDVR0jBBgwFoAUOUYGtUyheuxO4lGe4Op1y8NVoagw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANXLyfAs7J9rmBamGJvPZ
+ltx390WxzzLFQsBRAaH6rgeipBq3dR9qEjAwb6BTF+ROmtQzX+fjstCRrJxCto9W
+tC8KvXTdRfIjfCCZjhtIOBKqRxE4KJV/RBfv9xD5lyjtCPCQl3Ia6MSf42N+abAK
+WCdU6KCojA8WB9YhSCzza3aQbPTzd26OC/JblJpVgtus5f8ILzCsz+pbMimgTkhy
+AuhYRppJaQ24APijsEC9+GIaVKPg5IwWroiPoj+QXNpshuvqVQQXvGaRiq4zoSnx
+xAJz+w8tjrDWcf826VN14IL+/Cmqlg/rIfB5CHdwVIfWwpuGB66q/UiPegZMNs8a
+3g==
+-----END CERTIFICATE-----
diff --git a/Istio-Samples/cicd/skaffold/README.md b/Istio-Samples/cicd/skaffold/README.md
new file mode 100644
index 00000000..a8fa19ab
--- /dev/null
+++ b/Istio-Samples/cicd/skaffold/README.md
@@ -0,0 +1,45 @@
+# Skaffold
+
+This is intended for demonstration only, and is not tuned for performance or security.
+
+skaffold is a tool that enables fast development iteration and controls deployment to local or remote clusters
+
+If running `skaffold run` for deployment, manifests are pulled from remote charts, if running `skaffold dev` for development and hot reload, manifests are pulled from current branch.
+
+## Quick Start
+
+skaffold is built around modules and profiles
+
+1) istio-base + istio
+
+ ```bash
+ skaffold run -m istiod
+ ```
+
+2) istio-base + istio + ingress
+
+ ```bash
+ skaffold run -m ingress
+ ```
+
+3) istio-base + istio + ingress + kiali
+
+ ```bash
+ skaffold run -m ingress,kiali
+ ```
+
+4) istio-base + istio + ingress + kiali + bookinfo
+
+ ```bash
+ skaffold run -m ingress,kiali,bookinfo
+ ```
+
+## References
+
+- Github: [github.com/GoogleContainerTools/skaffold](https://github.com/GoogleContainerTools/skaffold)
+- Site: [skaffold.dev](https://skaffold.dev/)
+
+### TODO
+
+- Add build and test stage for images in istiod (pilot and proxy)
+- Addons
diff --git a/Istio-Samples/cicd/skaffold/skaffold.yaml b/Istio-Samples/cicd/skaffold/skaffold.yaml
new file mode 100644
index 00000000..b67aa289
--- /dev/null
+++ b/Istio-Samples/cicd/skaffold/skaffold.yaml
@@ -0,0 +1,145 @@
+# Skaffold - https://skaffold.dev/
+# ------------------------------------------------ #
+# This is for illustration purposes only
+# ------------------------------------------------ #
+# Installation options & modules
+# ------------------------------------------------ #
+# istio - `skaffold run -m istiod`
+# ingress - `skaffold run -m ingress`
+# Addons:
+# - kiali - `skaffold run -m kiali`
+# - prometheus - `skaffold run -m prometheus`
+# Demos:
+# - bookinfo - `skaffold run -m bookinfo`
+# ------------------------------------------------ #
+# Development mode - skaffold dev #
+# ------------------------------------------------- #
+apiVersion: skaffold/v2beta22
+kind: Config
+metadata:
+ name: istio-base
+profiles:
+ - name: dev
+ activation:
+ - command: dev
+ deploy:
+ helm:
+ releases:
+ - name: istio-base
+ chartPath: ../../../manifests/charts/base
+ namespace: istio-system
+ createNamespace: true
+ - name: run
+ activation:
+ - command: run
+ deploy:
+ helm:
+ releases:
+ - name: istio-base
+ remoteChart: base
+ repo: https://istio-release.storage.googleapis.com/charts
+ namespace: istio-system
+ createNamespace: true
+---
+apiVersion: skaffold/v2beta22
+kind: Config
+metadata:
+ name: istiod
+requires:
+ - configs: [istio-base]
+profiles:
+ - name: dev
+ activation:
+ - command: dev
+ deploy:
+ helm:
+ releases:
+ - name: istiod
+ chartPath: ../../../manifests/charts/istio-control/istio-discovery
+ namespace: istio-system
+ - name: run
+ activation:
+ - command: run
+ deploy:
+ helm:
+ releases:
+ - name: istiod
+ remoteChart: istiod
+ repo: https://istio-release.storage.googleapis.com/charts
+ namespace: istio-system
+---
+apiVersion: skaffold/v2beta22
+kind: Config
+metadata:
+ name: ingress
+requires:
+ - configs: [istiod]
+profiles:
+ - name: dev
+ activation:
+ - command: dev
+ deploy:
+ helm:
+ releases:
+ - name: istio-ingressgateway
+ chartPath: ../../../manifests/charts/gateway
+ namespace: istio-system
+ - name: run
+ activation:
+ - command: run
+ deploy:
+ helm:
+ releases:
+ - name: istio-ingressgateway
+ remoteChart: gateway
+ repo: https://istio-release.storage.googleapis.com/charts
+ namespace: istio-system
+---
+# https://istio.io/latest/docs/ops/integrations/prometheus/
+apiVersion: skaffold/v2beta22
+kind: Config
+metadata:
+ name: prometheus
+requires:
+ - configs: [istiod]
+deploy:
+ kubectl:
+ manifests: ["../../../samples/addons/prometheus.yaml"]
+---
+apiVersion: skaffold/v2beta22
+kind: Config
+metadata:
+ name: kiali
+requires:
+ - configs: [prometheus]
+deploy:
+ helm:
+ releases:
+ - name: kiali-server
+ remoteChart: kiali-server
+ repo: https://kiali.org/helm-charts
+ namespace: istio-system
+ version: v1.44.0
+ valuesFiles: [../../../manifests/addons/values-kiali.yaml]
+---
+# Config for https://istio.io/latest/docs/examples/bookinfo/
+apiVersion: skaffold/v2beta22
+kind: Config
+metadata:
+ name: bookinfo
+requires:
+ - configs: [ingress]
+deploy:
+ kubectl:
+ hooks:
+ before:
+ - host:
+ command: ["sh", "-c", "kubectl label namespace default istio-injection=enabled --overwrite"]
+ os: [darwin, linux]
+ - host:
+ command: ["cmd.exe", "/C", "kubectl label namespace default istio-injection=enabled --overwrite"]
+ os: [windows]
+ manifests:
+ - "../../../samples/bookinfo/platform/kube/bookinfo.yaml"
+ - "../../../samples/bookinfo/networking/bookinfo-gateway.yaml"
+ - "../../../samples/bookinfo/networking/destination-rule-all.yaml"
diff --git a/Istio-Samples/custom-bootstrap/README.md b/Istio-Samples/custom-bootstrap/README.md
new file mode 100644
index 00000000..814e7dcc
--- /dev/null
+++ b/Istio-Samples/custom-bootstrap/README.md
@@ -0,0 +1,52 @@
+# Custom Envoy Bootstrap Configuration
+
+This sample creates a simple helloworld service that bootstraps the Envoy proxy with a custom configuration file.
+
+## Starting the service
+
+First, we need to create a `ConfigMap` resource with our bootstrap configuration.
+
+```bash
+kubectl apply -f custom-bootstrap.yaml
+```
+
+Next, we can create a service that uses this bootstrap configuration.
+
+To do this, we need to add an annotation, `sidecar.istio.io/bootstrapOverride`, with the name of our ConfigMap as the value.
+
+We can create our helloworld app, using the custom config, with:
+
+```bash
+kubectl apply -f example-app.yaml
+```
+
+If you don't have [automatic sidecar injection](https://istio.io/docs/setup/additional-setup/sidecar-injection/#automatic-sidecar-injection)
+set in your cluster you will need to manually inject it to the services instead:
+
+```bash
+istioctl kube-inject -f example-app.yaml -o example-app-istio.yaml
+kubectl apply -f example-app-istio.yaml
+```
+
+## Checking the Bootstrap Configuration
+
+To see what bootstrap configuration a pod is using:
+
+```bash
+istioctl proxy-config bootstrap
+```
+
+## Customizing the Bootstrap
+
+The configuration provided will be passed to envoy using the [`--config-yaml`](https://www.envoyproxy.io/docs/envoy/v1.7.1/operations/cli#cmdoption-config-yaml) flag.
+
+This will merge the passed in configuration with the default configuration. Singular values will replace the default values, while repeated values will be appended.
+
+For reference, [the default bootstrap configuration](../../tools/packaging/common/envoy_bootstrap.json) and Envoy's [configuration reference](https://www.envoyproxy.io/docs/envoy/latest/configuration/configuration#config) may be useful
+
+## Cleanup
+
+```bash
+kubectl delete -f custom-bootstrap.yaml
+kubectl delete -f example-app.yaml
+```
diff --git a/Istio-Samples/custom-bootstrap/custom-bootstrap.yaml b/Istio-Samples/custom-bootstrap/custom-bootstrap.yaml
new file mode 100644
index 00000000..5f406976
--- /dev/null
+++ b/Istio-Samples/custom-bootstrap/custom-bootstrap.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: istio-custom-bootstrap-config
+ namespace: default
+data:
+ custom_bootstrap.json: |
+ "tracing": {
+ "http": {
+ "name": "envoy.tracers.zipkin",
+ "typed_config": {
+ "@type": "type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
+ "collector_cluster": "zipkin",
+ "collector_endpoint": "/api/v1/spans/custom",
+ "collector_endpoint_version": "HTTP_JSON",
+ "trace_id_128bit": true,
+ "shared_span_context": false
+ }
+ }
+ }
diff --git a/Istio-Samples/custom-bootstrap/example-app.yaml b/Istio-Samples/custom-bootstrap/example-app.yaml
new file mode 100644
index 00000000..3a351a31
--- /dev/null
+++ b/Istio-Samples/custom-bootstrap/example-app.yaml
@@ -0,0 +1,30 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: helloworld-v1
+ labels:
+ app: helloworld
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: helloworld
+ version: v1
+ template:
+ metadata:
+ annotations:
+ sidecar.istio.io/bootstrapOverride: "istio-custom-bootstrap-config"
+ labels:
+ app: helloworld
+ version: v1
+ spec:
+ containers:
+ - name: helloworld
+ image: docker.io/istio/examples-helloworld-v1
+ resources:
+ requests:
+ cpu: "100m"
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 5000
diff --git a/Istio-Samples/extauthz/README.md b/Istio-Samples/extauthz/README.md
new file mode 100644
index 00000000..8cefb664
--- /dev/null
+++ b/Istio-Samples/extauthz/README.md
@@ -0,0 +1,99 @@
+# Ext Authz Service
+
+[Ext Authz server](cmd/extauthz) implements the external server for the [Envoy ext_authz filter](https://www.envoyproxy.io/docs/envoy/v1.16.0/intro/arch_overview/security/ext_authz_filter)
+as an example of integrating custom authorization system into Istio.
+
+The Ext Authz server supports authorization check request using either HTTP (port 8000) or gRPC v2/v3 (port 9000) API and
+will allow the request if it includes the header `x-ext-authz: allow` or if the service account of the source workload is `a`.
+Note that `a` is just a default value for testing. It can be changed with the flag `-allow_service_account` when running the ext authz server.
+
+## Usage
+
+1. Deploy the Ext Authz service in a dedicated pod:
+
+ ```console
+ $ kubectl apply -f ext-authz.yaml
+ service/ext-authz created
+ deployment.apps/ext-authz created
+ ```
+
+ Note, you can also deploy the Ext Authz service locally with the application container in the same pod, see the example in `local-ext-authz.yaml`.
+
+1. Verify the Ext Authz server is up and running:
+
+ Deploy a sleep pod to send the request:
+
+ ```console
+ $ kubectl apply -f ../sleep/sleep.yaml
+ ```
+
+ Send a check request with header `x-ext-authz: allow` to the Ext Authz server:
+
+ ```console
+ $ kubectl exec -it $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c sleep -- curl -v ext-authz:8000 -H "x-ext-authz: allow"
+ * Trying 10.97.88.183:8000...
+ * Connected to ext-authz-server (10.97.88.183) port 8000 (#0)
+ > GET / HTTP/1.1
+ > Host: ext-authz-server:8000
+ > User-Agent: curl/7.73.0-DEV
+ > Accept: */*
+ > x-ext-authz: allow
+ >
+ * Mark bundle as not supporting multiuse
+ < HTTP/1.1 200 OK
+ < x-ext-authz-result: allowed
+ < date: Tue, 03 Nov 2020 03:06:11 GMT
+ < content-length: 0
+ < x-envoy-upstream-service-time: 19
+ < server: envoy
+ <
+ * Connection #0 to host ext-authz-server left intact
+ ```
+
+ As you observe, the check request with header `x-ext-authz: allow` is allowed by the Ext Authz server.
+
+ Send another check request with `x-ext-authz: blabla` to the Ext Authz server:
+
+ ```console
+ $ kubectl exec -it $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c sleep -- curl -v ext-authz:8000 -H "x-ext-authz: bla"
+ > GET / HTTP/1.1
+ > Host: ext-authz-server:8000
+ > User-Agent: curl/7.73.0-DEV
+ > Accept: */*
+ > x-ext-authz: allowx
+ >
+ * Mark bundle as not supporting multiuse
+ < HTTP/1.1 403 Forbidden
+ < x-ext-authz-check-result: denied
+ < date: Tue, 03 Nov 2020 03:14:02 GMT
+ < content-length: 76
+ < content-type: text/plain; charset=utf-8
+ < x-envoy-upstream-service-time: 44
+ < server: envoy
+ <
+ * Connection #0 to host ext-authz-server left intact
+ denied by ext_authz for not found header `x-ext-authz: allow` in the request
+ ```
+
+ As you observe, the check request with header `x-ext-authz: bla` is denied by the Ext Authz server.
+
+1. To clean up, execute the following commands:
+
+ ```console
+ $ kubectl delete -f ../sleep/sleep.yaml
+ $ kubectl delete -f ext-authz.yaml
+ ```
+
+## Advanced features
+
+The Ext Authz server supports the following advanced features that are useful for testing:
+
+- The ext authz server will add the `x-ext-authz-check-received` header to the user request. The content is the dump of
+ the check request it received from the ext-authz filter. This header is useful in verifying the ext-authz filter sending
+ the expected request to the ext authz server.
+
+- The ext authz server will add (or override if it already exists) the header `x-ext-authz-additional-header-override` to
+ the user request. The value of the header depends on the type of ext-authz server.
+ The ext authz HTTP server will set it to the value of the same `x-ext-authz-additional-header-override` header in the
+ check request. The ext authz gRPC server will set it to the constant value `grpc-additional-header-override-value`.
+ This header is useful in verifying the header override behavior in the ext-authz filter.
diff --git a/Istio-Samples/extauthz/cmd/extauthz/main.go b/Istio-Samples/extauthz/cmd/extauthz/main.go
new file mode 100644
index 00000000..6d4f4999
--- /dev/null
+++ b/Istio-Samples/extauthz/cmd/extauthz/main.go
@@ -0,0 +1,360 @@
+// Copyright Istio Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "net/http"
+ "os"
+ "os/signal"
+ "strings"
+ "sync"
+ "syscall"
+
+ corev2 "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
+ corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
+ authv2 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v2"
+ authv3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
+ typev2 "github.com/envoyproxy/go-control-plane/envoy/type"
+ typev3 "github.com/envoyproxy/go-control-plane/envoy/type/v3"
+ "google.golang.org/genproto/googleapis/rpc/status"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+)
+
+const (
+ checkHeader = "x-ext-authz"
+ allowedValue = "allow"
+ resultHeader = "x-ext-authz-check-result"
+ receivedHeader = "x-ext-authz-check-received"
+ overrideHeader = "x-ext-authz-additional-header-override"
+ overrideGRPCValue = "grpc-additional-header-override-value"
+ resultAllowed = "allowed"
+ resultDenied = "denied"
+)
+
+var (
+ serviceAccount = flag.String("allow_service_account", "a",
+ "allowed service account, matched against the service account in the source principal from the client certificate")
+ httpPort = flag.String("http", "8000", "HTTP server port")
+ grpcPort = flag.String("grpc", "9000", "gRPC server port")
+ denyBody = fmt.Sprintf("denied by ext_authz for not found header `%s: %s` in the request", checkHeader, allowedValue)
+)
+
+type (
+ extAuthzServerV2 struct{}
+ extAuthzServerV3 struct{}
+)
+
+// ExtAuthzServer implements the ext_authz v2/v3 gRPC and HTTP check request API.
+type ExtAuthzServer struct {
+ grpcServer *grpc.Server
+ httpServer *http.Server
+ grpcV2 *extAuthzServerV2
+ grpcV3 *extAuthzServerV3
+ // For test only
+ httpPort chan int
+ grpcPort chan int
+}
+
+func (s *extAuthzServerV2) logRequest(allow string, request *authv2.CheckRequest) {
+ httpAttrs := request.GetAttributes().GetRequest().GetHttp()
+ log.Printf("[gRPCv2][%s]: %s%s, attributes: %v\n", allow, httpAttrs.GetHost(),
+ httpAttrs.GetPath(),
+ request.GetAttributes())
+}
+
+func (s *extAuthzServerV2) allow(request *authv2.CheckRequest) *authv2.CheckResponse {
+ s.logRequest("allowed", request)
+ return &authv2.CheckResponse{
+ HttpResponse: &authv2.CheckResponse_OkResponse{
+ OkResponse: &authv2.OkHttpResponse{
+ Headers: []*corev2.HeaderValueOption{
+ {
+ Header: &corev2.HeaderValue{
+ Key: resultHeader,
+ Value: resultAllowed,
+ },
+ },
+ {
+ Header: &corev2.HeaderValue{
+ Key: receivedHeader,
+ Value: request.GetAttributes().String(),
+ },
+ },
+ {
+ Header: &corev2.HeaderValue{
+ Key: overrideHeader,
+ Value: overrideGRPCValue,
+ },
+ },
+ },
+ },
+ },
+ Status: &status.Status{Code: int32(codes.OK)},
+ }
+}
+
+func (s *extAuthzServerV2) deny(request *authv2.CheckRequest) *authv2.CheckResponse {
+ s.logRequest("denied", request)
+ return &authv2.CheckResponse{
+ HttpResponse: &authv2.CheckResponse_DeniedResponse{
+ DeniedResponse: &authv2.DeniedHttpResponse{
+ Status: &typev2.HttpStatus{Code: typev2.StatusCode_Forbidden},
+ Body: denyBody,
+ Headers: []*corev2.HeaderValueOption{
+ {
+ Header: &corev2.HeaderValue{
+ Key: resultHeader,
+ Value: resultDenied,
+ },
+ },
+ {
+ Header: &corev2.HeaderValue{
+ Key: receivedHeader,
+ Value: request.GetAttributes().String(),
+ },
+ },
+ {
+ Header: &corev2.HeaderValue{
+ Key: overrideHeader,
+ Value: overrideGRPCValue,
+ },
+ },
+ },
+ },
+ },
+ Status: &status.Status{Code: int32(codes.PermissionDenied)},
+ }
+}
+
+// Check implements gRPC v2 check request.
+func (s *extAuthzServerV2) Check(_ context.Context, request *authv2.CheckRequest) (*authv2.CheckResponse, error) {
+ attrs := request.GetAttributes()
+
+ // Determine whether to allow or deny the request.
+ allow := false
+ checkHeaderValue, contains := attrs.GetRequest().GetHttp().GetHeaders()[checkHeader]
+ if contains {
+ allow = checkHeaderValue == allowedValue
+ } else {
+ allow = attrs.Source != nil && strings.HasSuffix(attrs.Source.Principal, "/sa/"+*serviceAccount)
+ }
+
+ if allow {
+ return s.allow(request), nil
+ }
+
+ return s.deny(request), nil
+}
+
+func (s *extAuthzServerV3) logRequest(allow string, request *authv3.CheckRequest) {
+ httpAttrs := request.GetAttributes().GetRequest().GetHttp()
+ log.Printf("[gRPCv3][%s]: %s%s, attributes: %v\n", allow, httpAttrs.GetHost(),
+ httpAttrs.GetPath(),
+ request.GetAttributes())
+}
+
+func (s *extAuthzServerV3) allow(request *authv3.CheckRequest) *authv3.CheckResponse {
+ s.logRequest("allowed", request)
+ return &authv3.CheckResponse{
+ HttpResponse: &authv3.CheckResponse_OkResponse{
+ OkResponse: &authv3.OkHttpResponse{
+ Headers: []*corev3.HeaderValueOption{
+ {
+ Header: &corev3.HeaderValue{
+ Key: resultHeader,
+ Value: resultAllowed,
+ },
+ },
+ {
+ Header: &corev3.HeaderValue{
+ Key: receivedHeader,
+ Value: request.GetAttributes().String(),
+ },
+ },
+ {
+ Header: &corev3.HeaderValue{
+ Key: overrideHeader,
+ Value: overrideGRPCValue,
+ },
+ },
+ },
+ },
+ },
+ Status: &status.Status{Code: int32(codes.OK)},
+ }
+}
+
+func (s *extAuthzServerV3) deny(request *authv3.CheckRequest) *authv3.CheckResponse {
+ s.logRequest("denied", request)
+ return &authv3.CheckResponse{
+ HttpResponse: &authv3.CheckResponse_DeniedResponse{
+ DeniedResponse: &authv3.DeniedHttpResponse{
+ Status: &typev3.HttpStatus{Code: typev3.StatusCode_Forbidden},
+ Body: denyBody,
+ Headers: []*corev3.HeaderValueOption{
+ {
+ Header: &corev3.HeaderValue{
+ Key: resultHeader,
+ Value: resultDenied,
+ },
+ },
+ {
+ Header: &corev3.HeaderValue{
+ Key: receivedHeader,
+ Value: request.GetAttributes().String(),
+ },
+ },
+ {
+ Header: &corev3.HeaderValue{
+ Key: overrideHeader,
+ Value: overrideGRPCValue,
+ },
+ },
+ },
+ },
+ },
+ Status: &status.Status{Code: int32(codes.PermissionDenied)},
+ }
+}
+
+// Check implements gRPC v3 check request.
+func (s *extAuthzServerV3) Check(_ context.Context, request *authv3.CheckRequest) (*authv3.CheckResponse, error) {
+ attrs := request.GetAttributes()
+
+ // Determine whether to allow or deny the request.
+ allow := false
+ checkHeaderValue, contains := attrs.GetRequest().GetHttp().GetHeaders()[checkHeader]
+ if contains {
+ allow = checkHeaderValue == allowedValue
+ } else {
+ allow = attrs.Source != nil && strings.HasSuffix(attrs.Source.Principal, "/sa/"+*serviceAccount)
+ }
+
+ if allow {
+ return s.allow(request), nil
+ }
+
+ return s.deny(request), nil
+}
+
+// ServeHTTP implements the HTTP check request.
+func (s *ExtAuthzServer) ServeHTTP(response http.ResponseWriter, request *http.Request) {
+ body, err := io.ReadAll(request.Body)
+ if err != nil {
+ log.Printf("[HTTP] read body failed: %v", err)
+ }
+ l := fmt.Sprintf("%s %s%s, headers: %v, body: [%s]\n", request.Method, request.Host, request.URL, request.Header, body)
+ if allowedValue == request.Header.Get(checkHeader) {
+ log.Printf("[HTTP][allowed]: %s", l)
+ response.Header().Set(resultHeader, resultAllowed)
+ response.Header().Set(overrideHeader, request.Header.Get(overrideHeader))
+ response.Header().Set(receivedHeader, l)
+ response.WriteHeader(http.StatusOK)
+ } else {
+ log.Printf("[HTTP][denied]: %s", l)
+ response.Header().Set(resultHeader, resultDenied)
+ response.Header().Set(overrideHeader, request.Header.Get(overrideHeader))
+ response.Header().Set(receivedHeader, l)
+ response.WriteHeader(http.StatusForbidden)
+ _, _ = response.Write([]byte(denyBody))
+ }
+}
+
+func (s *ExtAuthzServer) startGRPC(address string, wg *sync.WaitGroup) {
+ defer func() {
+ wg.Done()
+ log.Printf("Stopped gRPC server")
+ }()
+
+ listener, err := net.Listen("tcp", address)
+ if err != nil {
+ log.Fatalf("Failed to start gRPC server: %v", err)
+ return
+ }
+ // Store the port for test only.
+ s.grpcPort <- listener.Addr().(*net.TCPAddr).Port
+
+ s.grpcServer = grpc.NewServer()
+ authv2.RegisterAuthorizationServer(s.grpcServer, s.grpcV2)
+ authv3.RegisterAuthorizationServer(s.grpcServer, s.grpcV3)
+
+ log.Printf("Starting gRPC server at %s", listener.Addr())
+ if err := s.grpcServer.Serve(listener); err != nil {
+ log.Fatalf("Failed to serve gRPC server: %v", err)
+ return
+ }
+}
+
+func (s *ExtAuthzServer) startHTTP(address string, wg *sync.WaitGroup) {
+ defer func() {
+ wg.Done()
+ log.Printf("Stopped HTTP server")
+ }()
+
+ listener, err := net.Listen("tcp", address)
+ if err != nil {
+ log.Fatalf("Failed to create HTTP server: %v", err)
+ }
+ // Store the port for test only.
+ s.httpPort <- listener.Addr().(*net.TCPAddr).Port
+ s.httpServer = &http.Server{Handler: s}
+
+ log.Printf("Starting HTTP server at %s", listener.Addr())
+ if err := s.httpServer.Serve(listener); err != nil {
+ log.Fatalf("Failed to start HTTP server: %v", err)
+ }
+}
+
+func (s *ExtAuthzServer) run(httpAddr, grpcAddr string) {
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go s.startHTTP(httpAddr, &wg)
+ go s.startGRPC(grpcAddr, &wg)
+ wg.Wait()
+}
+
+func (s *ExtAuthzServer) stop() {
+ s.grpcServer.Stop()
+ log.Printf("GRPC server stopped")
+ log.Printf("HTTP server stopped: %v", s.httpServer.Close())
+}
+
+func NewExtAuthzServer() *ExtAuthzServer {
+ return &ExtAuthzServer{
+ grpcV2: &extAuthzServerV2{},
+ grpcV3: &extAuthzServerV3{},
+ httpPort: make(chan int, 1),
+ grpcPort: make(chan int, 1),
+ }
+}
+
+func main() {
+ flag.Parse()
+ s := NewExtAuthzServer()
+ go s.run(fmt.Sprintf(":%s", *httpPort), fmt.Sprintf(":%s", *grpcPort))
+ defer s.stop()
+
+ // Wait for the process to be shutdown.
+ sigs := make(chan os.Signal, 1)
+ signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
+ <-sigs
+}
diff --git a/Istio-Samples/extauthz/cmd/extauthz/main_test.go b/Istio-Samples/extauthz/cmd/extauthz/main_test.go
new file mode 100644
index 00000000..ee64a76b
--- /dev/null
+++ b/Istio-Samples/extauthz/cmd/extauthz/main_test.go
@@ -0,0 +1,145 @@
+// Copyright Istio Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "testing"
+
+ authv2 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v2"
+ authv3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/credentials/insecure"
+)
+
+func TestExtAuthz(t *testing.T) {
+ server := NewExtAuthzServer()
+ // Start the test server on random port.
+ go server.run("localhost:0", "localhost:0")
+
+ // Prepare the HTTP request.
+ httpClient := &http.Client{}
+ httpReq, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://localhost:%d/check", <-server.httpPort), nil)
+ if err != nil {
+ t.Fatalf(err.Error())
+ }
+
+ // Prepare the gRPC request.
+ conn, err := grpc.Dial(fmt.Sprintf("localhost:%d", <-server.grpcPort), grpc.WithTransportCredentials(insecure.NewCredentials()))
+ if err != nil {
+ t.Fatalf(err.Error())
+ }
+ defer func() { _ = conn.Close() }()
+ grpcV3Client := authv3.NewAuthorizationClient(conn)
+ grpcV2Client := authv2.NewAuthorizationClient(conn)
+
+ cases := []struct {
+ name string
+ isGRPCV3 bool
+ isGRPCV2 bool
+ header string
+ want int
+ }{
+ {
+ name: "HTTP-allow",
+ header: "allow",
+ want: http.StatusOK,
+ },
+ {
+ name: "HTTP-deny",
+ header: "deny",
+ want: http.StatusForbidden,
+ },
+ {
+ name: "GRPCv3-allow",
+ isGRPCV3: true,
+ header: "allow",
+ want: int(codes.OK),
+ },
+ {
+ name: "GRPCv3-deny",
+ isGRPCV3: true,
+ header: "deny",
+ want: int(codes.PermissionDenied),
+ },
+ {
+ name: "GRPCv2-allow",
+ isGRPCV2: true,
+ header: "allow",
+ want: int(codes.OK),
+ },
+ {
+ name: "GRPCv2-deny",
+ isGRPCV2: true,
+ header: "deny",
+ want: int(codes.PermissionDenied),
+ },
+ }
+ for _, tc := range cases {
+ t.Run(tc.name, func(t *testing.T) {
+ var got int
+ if tc.isGRPCV3 {
+ resp, err := grpcV3Client.Check(context.Background(), &authv3.CheckRequest{
+ Attributes: &authv3.AttributeContext{
+ Request: &authv3.AttributeContext_Request{
+ Http: &authv3.AttributeContext_HttpRequest{
+ Host: "localhost",
+ Path: "/check",
+ Headers: map[string]string{checkHeader: tc.header},
+ },
+ },
+ },
+ })
+ if err != nil {
+ t.Errorf(err.Error())
+ } else {
+ got = int(resp.Status.Code)
+ }
+ } else if tc.isGRPCV2 {
+ resp, err := grpcV2Client.Check(context.Background(), &authv2.CheckRequest{
+ Attributes: &authv2.AttributeContext{
+ Request: &authv2.AttributeContext_Request{
+ Http: &authv2.AttributeContext_HttpRequest{
+ Host: "localhost",
+ Path: "/check",
+ Headers: map[string]string{checkHeader: tc.header},
+ },
+ },
+ },
+ })
+ if err != nil {
+ t.Errorf(err.Error())
+ } else {
+ got = int(resp.Status.Code)
+ }
+ } else {
+ httpReq.Header.Set(checkHeader, tc.header)
+ resp, err := httpClient.Do(httpReq)
+ if err != nil {
+ t.Errorf(err.Error())
+ } else {
+ got = resp.StatusCode
+ resp.Body.Close()
+ }
+ }
+ if got != tc.want {
+ t.Errorf("want %d but got %d", tc.want, got)
+ }
+ })
+ }
+}
diff --git a/Istio-Samples/extauthz/docker/Dockerfile b/Istio-Samples/extauthz/docker/Dockerfile
new file mode 100644
index 00000000..6ee622a1
--- /dev/null
+++ b/Istio-Samples/extauthz/docker/Dockerfile
@@ -0,0 +1,9 @@
+ARG BASE_VERSION=latest
+ARG ISTIO_BASE_REGISTRY=gcr.io/istio-release
+
+FROM ${ISTIO_BASE_REGISTRY}/base:${BASE_VERSION}
+
+ARG TARGETARCH
+COPY ${TARGETARCH:-amd64}/extauthz /usr/local/bin/extauthz
+
+ENTRYPOINT ["/usr/local/bin/extauthz"]
diff --git a/Istio-Samples/extauthz/ext-authz.yaml b/Istio-Samples/extauthz/ext-authz.yaml
new file mode 100644
index 00000000..0860df5c
--- /dev/null
+++ b/Istio-Samples/extauthz/ext-authz.yaml
@@ -0,0 +1,55 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Example configurations for deploying ext-authz server separately in the mesh.
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: ext-authz
+ labels:
+ app: ext-authz
+spec:
+ ports:
+ - name: http
+ port: 8000
+ targetPort: 8000
+ - name: grpc
+ port: 9000
+ targetPort: 9000
+ selector:
+ app: ext-authz
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: ext-authz
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ext-authz
+ template:
+ metadata:
+ labels:
+ app: ext-authz
+ spec:
+ containers:
+ - image: gcr.io/istio-testing/ext-authz:latest
+ imagePullPolicy: IfNotPresent
+ name: ext-authz
+ ports:
+ - containerPort: 8000
+ - containerPort: 9000
+---
diff --git a/Istio-Samples/extauthz/local-ext-authz.yaml b/Istio-Samples/extauthz/local-ext-authz.yaml
new file mode 100644
index 00000000..89a7625f
--- /dev/null
+++ b/Istio-Samples/extauthz/local-ext-authz.yaml
@@ -0,0 +1,111 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Example configurations for deploying ext-authz server locally with the application container in the same pod.
+
+# Define the service entry for the local ext-authz service on port 8000.
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: httpbin-ext-authz-http
+spec:
+ hosts:
+ - "ext-authz-http.local"
+ endpoints:
+ - address: "127.0.0.1"
+ ports:
+ - name: http
+ number: 8000
+ protocol: HTTP
+ resolution: STATIC
+---
+# Define the service entry for the local ext-authz service on port 9000.
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: httpbin-ext-authz-grpc
+spec:
+ hosts:
+ - "ext-authz-grpc.local"
+ endpoints:
+ - address: "127.0.0.1"
+ ports:
+ - name: grpc
+ number: 9000
+ protocol: GRPC
+ resolution: STATIC
+---
+# Deploy the ext-authz server locally with the application container in the same pod.
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: httpbin
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: httpbin
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: httpbin
+ version: v1
+ spec:
+ serviceAccountName: httpbin
+ containers:
+ - image: docker.io/kong/httpbin
+ imagePullPolicy: IfNotPresent
+ name: httpbin
+ # Same as found in Dockerfile's CMD but using an unprivileged port
+ command:
+ - gunicorn
+ - -b
+ - 0.0.0.0:8080
+ - httpbin:app
+ - -k
+ - gevent
+ env:
+ # Tells pipenv to use a writable directory instead of $HOME
+ - name: WORKON_HOME
+ value: /tmp
+ ports:
+ - containerPort: 8080
+ - image: gcr.io/istio-testing/ext-authz:latest
+ imagePullPolicy: IfNotPresent
+ name: ext-authz
+ ports:
+ - containerPort: 8000
+ - containerPort: 9000
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: httpbin
+ labels:
+ app: httpbin
+ service: httpbin
+spec:
+ ports:
+ - name: http
+ port: 8000
+ targetPort: 8080
+ selector:
+ app: httpbin
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: httpbin
+---
diff --git a/Istio-Samples/external/README.md b/Istio-Samples/external/README.md
new file mode 100644
index 00000000..8f7d9c48
--- /dev/null
+++ b/Istio-Samples/external/README.md
@@ -0,0 +1,34 @@
+# External Services
+
+By default, Istio-enabled services are unable to access services and URLs outside the cluster. Pods use iptables to transparently redirect all outbound traffic to the sidecar proxy, which only handles intra-cluster destinations.
+
+See [the Egress Task](https://istio.io/docs/tasks/traffic-management/egress/) for
+information on configuring Istio to contact external services.
+
+This directory contains samples showing how to enable pods to contact a few well
+known services.
+
+If Istio is not configured to allow pods to contact external services, the pods will
+see errors such as 404s, HTTPS connection problems, and TCP connection problems. If
+ServiceEntries are misconfigured pods may see problems with server names.
+
+## Try it out
+
+After an operator runs `kubectl create -f aptget.yaml` pods will be able to
+succeed with `apt-get update` and `apt-get install`.
+
+After an operator runs `kubectl create -f github.yaml` pods will be able to
+succeed with `git clone https://github.com/fortio/fortio.git`.
+
+Running `kubectl create -f pypi.yaml` allows pods to update Python libraries using `pip`.
+
+It is not a best practice to enable pods to update libraries dynamically.
+We are providing these samples
+because they have proven to be helpful with interactive troubleshooting. Security minded clusters should only allow traffic to service dependencies such as cloud
+services.
+
+### Enable communication by default
+
+Note that [this note](https://istio.io/docs/tasks/traffic-management/egress/#install-istio-with-access-to-all-external-services-by-default) shows how to configure Istio to contact services by default. The technique
+discussed there does not allow HTTP on port 80 or SSH on port 22. These examples will
+allow external communication for ports 80 and 22.
diff --git a/Istio-Samples/external/aptget.yaml b/Istio-Samples/external/aptget.yaml
new file mode 100644
index 00000000..fa24fa45
--- /dev/null
+++ b/Istio-Samples/external/aptget.yaml
@@ -0,0 +1,20 @@
+# This ServiceEntry exposes the hosts needed for installing packages with apt-get.
+# After applying this file, Istio-enabled pods (configured apt-get) be able to execute
+# `apt-get upgrade` and `apt-get install`. If this is not installed you may get
+# "404 Not Found"
+
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: make-aptget-work
+spec:
+ hosts:
+ - deb.debian.org
+ - cdn-fastly.deb.debian.org
+ - security.debian.org
+ - archive.ubuntu.com
+ - security.ubuntu.com
+ ports:
+ - number: 80
+ name: http
+ protocol: HTTP
diff --git a/Istio-Samples/external/github.yaml b/Istio-Samples/external/github.yaml
new file mode 100644
index 00000000..832cbc37
--- /dev/null
+++ b/Istio-Samples/external/github.yaml
@@ -0,0 +1,53 @@
+# This ServiceEntry exposes the hosts needed for github.com.
+# After applying this file, Istio-enabled pods will be able to execute
+# `git clone https://github.com/istio/api.git` and (with local identification
+# config and certificate) `git clone git@github.com:istio/api.git`
+
+# HTTP and TLS, the host must be specified
+# See https://istio.io/docs/tasks/traffic-management/egress/
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: github-https
+spec:
+ hosts:
+ - github.com
+ ports:
+ - number: 443
+ name: https
+ protocol: HTTPS
+---
+# For TCP services the IP ranges SHOULD be specified to avoid problems
+# if multiple SEs use the same port number.
+# See https://istio.io/blog/2018/egress-tcp/#mesh-external-service-entry-for-an-external-mysql-instance
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: github-tcp
+spec:
+ hosts:
+ - dummy.github.com # not used
+ addresses: # from https://help.github.com/articles/about-github-s-ip-addresses/
+ - "13.229.188.59/32"
+ - "13.250.177.223/32"
+ - "140.82.112.0/20"
+ - "18.194.104.89/32"
+ - "18.195.85.27/32"
+ - "185.199.108.0/22"
+ - "185.199.108.153/32"
+ - "185.199.109.153/32"
+ - "185.199.110.153/32"
+ - "185.199.111.153/32"
+ - "192.30.252.0/22"
+ - "192.30.252.153/32"
+ - "192.30.252.154/32"
+ - "23.20.92.3/32"
+ - "35.159.8.160/32"
+ - "52.74.223.119/32"
+ - "54.166.52.62/32"
+ - "54.87.5.173/32"
+ ports:
+ - name: tcp
+ number: 22
+ protocol: tcp
+ location: MESH_EXTERNAL
diff --git a/Istio-Samples/external/pypi.yaml b/Istio-Samples/external/pypi.yaml
new file mode 100644
index 00000000..7f457a5a
--- /dev/null
+++ b/Istio-Samples/external/pypi.yaml
@@ -0,0 +1,44 @@
+# This ServiceEntry exposes the hosts needed for Python `pip`.
+# After applying this file, Istio-enabled pods will be able to execute
+# `pip search istio`.
+
+# HTTP and TLS, the host must be specified
+# See https://istio.io/docs/tasks/traffic-management/egress/
+
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: python-https
+spec:
+ hosts:
+ - pypi.python.org
+ ports:
+ - number: 443
+ name: https
+ protocol: HTTPS
+---
+# pypi.python.org may 301 redirect to pypi.org, so we need this too.
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: pypi-https
+spec:
+ hosts:
+ - pypi.org
+ ports:
+ - number: 443
+ name: https
+ protocol: HTTPS
+---
+# pip install may fetch files from files.pythonhosted.org
+apiVersion: networking.istio.io/v1alpha3
+kind: ServiceEntry
+metadata:
+ name: pythonhosted-https
+spec:
+ hosts:
+ - files.pythonhosted.org
+ ports:
+ - number: 443
+ name: https
+ protocol: HTTPS
diff --git a/Istio-Samples/grpc-echo/README.md b/Istio-Samples/grpc-echo/README.md
new file mode 100644
index 00000000..46631698
--- /dev/null
+++ b/Istio-Samples/grpc-echo/README.md
@@ -0,0 +1,7 @@
+# grpc-echo
+
+This sample demonstrates Istio's Proxyless gRPC support with a special injection template `grpc-agent`.
+The template injects the `istio-proxy` sidecar, but the sidecar will only run `pilot-agent` and not envoy.
+
+See the [gRPC xDS feature status](https://github.com/grpc/grpc/blob/master/doc/grpc_xds_features.md) for more
+information.
diff --git a/Istio-Samples/grpc-echo/grpc-echo.yaml b/Istio-Samples/grpc-echo/grpc-echo.yaml
new file mode 100644
index 00000000..2dc6fd9a
--- /dev/null
+++ b/Istio-Samples/grpc-echo/grpc-echo.yaml
@@ -0,0 +1,191 @@
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ app: echo
+ name: echo
+ namespace: echo-grpc
+spec:
+ selector:
+ app: echo
+ type: ClusterIP
+ ports:
+ - name: http
+ port: 80
+ targetPort: 18080
+ - name: grpc
+ port: 7070
+ targetPort: 17070
+ - name: tcp
+ port: 9090
+ targetPort: 19090
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: echo-v1
+ namespace: echo-grpc
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: echo
+ version: v1
+ template:
+ metadata:
+ annotations:
+ inject.istio.io/templates: grpc-agent
+ proxy.istio.io/config: '{"holdApplicationUntilProxyStarts": true}'
+ labels:
+ app: echo
+ version: v1
+ spec:
+ containers:
+ - args:
+ - --metrics=15014
+ - --port
+ - "18080"
+ - --tcp
+ - "19090"
+ - --xds-grpc-server=17070
+ - --grpc
+ - "17070"
+ - --grpc
+ - "17171"
+ - --port
+ - "3333"
+ - --port
+ - "8080"
+ - --version
+ - v1
+ - --crt=/cert.crt
+ - --key=/cert.key
+ env:
+ - name: INSTANCE_IP
+ valueFrom:
+ fieldRef:
+ apiVersion: v1
+ fieldPath: status.podIP
+ image: gcr.io/istio-testing/app:latest
+ imagePullPolicy: Always
+ livenessProbe:
+ failureThreshold: 10
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ successThreshold: 1
+ tcpSocket:
+ port: tcp-health-port
+ timeoutSeconds: 1
+ name: app
+ ports:
+ - containerPort: 17070
+ protocol: TCP
+ - containerPort: 17171
+ protocol: TCP
+ - containerPort: 8080
+ protocol: TCP
+ - containerPort: 3333
+ name: tcp-health-port
+ protocol: TCP
+ readinessProbe:
+ failureThreshold: 10
+ httpGet:
+ path: /
+ port: 8080
+ scheme: HTTP
+ initialDelaySeconds: 1
+ periodSeconds: 2
+ successThreshold: 1
+ timeoutSeconds: 1
+ startupProbe:
+ failureThreshold: 10
+ periodSeconds: 10
+ successThreshold: 1
+ tcpSocket:
+ port: tcp-health-port
+ timeoutSeconds: 1
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: echo-v2
+ namespace: echo-grpc
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: echo
+ version: v2
+ template:
+ metadata:
+ annotations:
+ inject.istio.io/templates: grpc-agent
+ proxy.istio.io/config: '{"holdApplicationUntilProxyStarts": true}'
+ labels:
+ app: echo
+ version: v2
+ spec:
+ containers:
+ - args:
+ - --metrics=15014
+ - --xds-grpc-server=17070
+ - --port
+ - "18080"
+ - --tcp
+ - "19090"
+ - --grpc
+ - "17070"
+ - --grpc
+ - "17171"
+ - --port
+ - "3333"
+ - --port
+ - "8080"
+ - --version
+ - v2
+ - --crt=/cert.crt
+ - --key=/cert.key
+ env:
+ - name: INSTANCE_IP
+ valueFrom:
+ fieldRef:
+ apiVersion: v1
+ fieldPath: status.podIP
+ image: gcr.io/istio-testing/app:latest
+ imagePullPolicy: Always
+ livenessProbe:
+ failureThreshold: 10
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ successThreshold: 1
+ tcpSocket:
+ port: tcp-health-port
+ timeoutSeconds: 1
+ name: app
+ ports:
+ - containerPort: 17070
+ protocol: TCP
+ - containerPort: 17171
+ protocol: TCP
+ - containerPort: 8080
+ protocol: TCP
+ - containerPort: 3333
+ name: tcp-health-port
+ protocol: TCP
+ readinessProbe:
+ failureThreshold: 10
+ httpGet:
+ path: /
+ port: 8080
+ scheme: HTTP
+ initialDelaySeconds: 1
+ periodSeconds: 2
+ successThreshold: 1
+ timeoutSeconds: 1
+ startupProbe:
+ failureThreshold: 10
+ periodSeconds: 10
+ successThreshold: 1
+ tcpSocket:
+ port: tcp-health-port
+ timeoutSeconds: 1
diff --git a/Istio-Samples/health-check/liveness-command.yaml b/Istio-Samples/health-check/liveness-command.yaml
new file mode 100644
index 00000000..247b55e5
--- /dev/null
+++ b/Istio-Samples/health-check/liveness-command.yaml
@@ -0,0 +1,58 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Liveness service
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: liveness
+ labels:
+ app: liveness
+ service: liveness
+spec:
+ ports:
+ - port: 80
+ name: http
+ selector:
+ app: liveness
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: liveness
+spec:
+ selector:
+ matchLabels:
+ app: liveness
+ template:
+ metadata:
+ labels:
+ app: liveness
+ spec:
+ containers:
+ - name: liveness
+ image: registry.k8s.io/busybox
+ args:
+ - /bin/sh
+ - -c
+ - touch /tmp/healthy; sleep 3600
+ livenessProbe:
+ exec:
+ command:
+ - cat
+ - /tmp/healthy
+ initialDelaySeconds: 5
+ periodSeconds: 5
diff --git a/Istio-Samples/health-check/liveness-http-same-port.yaml b/Istio-Samples/health-check/liveness-http-same-port.yaml
new file mode 100644
index 00000000..a39a3ff1
--- /dev/null
+++ b/Istio-Samples/health-check/liveness-http-same-port.yaml
@@ -0,0 +1,40 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: liveness-http
+ labels:
+ app: liveness-http
+ service: liveness-http
+spec:
+ ports:
+ - name: http
+ port: 8001
+ selector:
+ app: liveness-http
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: liveness-http
+spec:
+ selector:
+ matchLabels:
+ app: liveness-http
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: liveness-http
+ version: v1
+ spec:
+ containers:
+ - name: liveness-http
+ image: docker.io/istio/health:example
+ ports:
+ - containerPort: 8001
+ livenessProbe:
+ httpGet:
+ path: /foo
+ port: 8001
+ initialDelaySeconds: 5
+ periodSeconds: 5
diff --git a/Istio-Samples/health-check/server.go b/Istio-Samples/health-check/server.go
new file mode 100644
index 00000000..c23d13b5
--- /dev/null
+++ b/Istio-Samples/health-check/server.go
@@ -0,0 +1,56 @@
+// Copyright Istio Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "net/http"
+)
+
+func main() {
+ finish := make(chan bool)
+ server8001 := http.NewServeMux()
+ server8001.HandleFunc("/foo", foo8001)
+ server8001.HandleFunc("/bar", bar8001)
+
+ server8002 := http.NewServeMux()
+ server8002.HandleFunc("/foo", foo8002)
+ server8002.HandleFunc("/bar", bar8002)
+
+ go func() {
+ http.ListenAndServe(":8001", server8001)
+ }()
+
+ go func() {
+ http.ListenAndServe(":8002", server8002)
+ }()
+
+ <-finish
+}
+
+func foo8001(w http.ResponseWriter, _ *http.Request) {
+ w.Write([]byte("Listening on 8001: foo "))
+}
+
+func bar8001(w http.ResponseWriter, _ *http.Request) {
+ w.Write([]byte("Listening on 8001: bar "))
+}
+
+func foo8002(w http.ResponseWriter, _ *http.Request) {
+ w.Write([]byte("Listening on 8002: foo "))
+}
+
+func bar8002(w http.ResponseWriter, _ *http.Request) {
+ w.Write([]byte("Listening on 8002: bar "))
+}
diff --git a/Istio-Samples/helloworld/README.md b/Istio-Samples/helloworld/README.md
new file mode 100644
index 00000000..2d4b2fbc
--- /dev/null
+++ b/Istio-Samples/helloworld/README.md
@@ -0,0 +1,110 @@
+# Helloworld service
+
+This sample includes two versions of a simple helloworld service that returns its version
+and instance (hostname) when called.
+It can be used as a test service when experimenting with version routing.
+
+This service is also used to demonstrate canary deployments working in conjunction with autoscaling.
+See [Canary deployments using Istio](https://istio.io/blog/2017/0.1-canary).
+
+## Start the helloworld service
+
+The following commands assume you have
+[automatic sidecar injection](https://istio.io/docs/setup/additional-setup/sidecar-injection/#automatic-sidecar-injection)
+enabled in your cluster.
+If not, you'll need to modify them to include
+[manual sidecar injection](https://istio.io/docs/setup/additional-setup/sidecar-injection/#manual-sidecar-injection).
+
+To run both versions of the helloworld service, use the following command:
+
+```bash
+kubectl apply -f helloworld.yaml
+```
+
+Alternatively, you can run just one version at a time by first defining the service:
+
+```bash
+kubectl apply -f helloworld.yaml -l service=helloworld
+```
+
+and then deploying version v1, v2, or both:
+
+```bash
+kubectl apply -f helloworld.yaml -l version=v1
+kubectl apply -f helloworld.yaml -l version=v2
+```
+
+For even more flexibility, there is also a script, `gen-helloworld.sh`, that will
+generate YAML for the helloworld service. This script takes the following
+arguments:
+
+| Argument | Default | Description |
+|-----------------------|---------|------------------------------------------------------------------------|
+| `-h`,`--help` | | Prints usage information. |
+| `--version` | `v1` | Specifies the version that will be returned by the helloworld service. |
+| `--includeService` | `true` | If `true` the service will be included in the YAML. |
+| `--includeDeployment` | `true` | If `true` the deployment will be included in the YAML. |
+
+You can use this script to deploy a custom version:
+
+```bash
+./gen-helloworld.sh --version customversion | \
+ kubectl apply -f -
+```
+
+## Configure the helloworld gateway
+
+*___Note:___ Istio intends to make the Kubernetes [Gateway API](https://gateway-api.sigs.k8s.io/) the default API for traffic management [in the future](https://istio.io/latest/blog/2022/gateway-api-beta/). You can use the Gateway API to configure the helloworld service, instead of the classic Istio configuration model, by following the instructions in [./gateway-api/README.md](./gateway-api/README.md), instead of the instructions below.*
+
+Apply the helloworld gateway configuration:
+
+```bash
+kubectl apply -f helloworld-gateway.yaml
+```
+
+Follow [these instructions](https://istio.io/docs/tasks/traffic-management/ingress/ingress-control/#determining-the-ingress-ip-and-ports)
+to set the INGRESS_HOST and INGRESS_PORT variables and then confirm the sample is running using curl:
+
+```bash
+export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
+curl http://$GATEWAY_URL/hello
+```
+
+## Autoscale the services
+
+Note that a Kubernetes [Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/)
+only works if all containers in the pods request cpu. In this sample the deployment
+containers in `helloworld.yaml` are configured with the request.
+The injected istio-proxy containers also include cpu requests,
+making the helloworld service ready for autoscaling.
+
+Enable autoscaling on both versions of the service:
+
+```bash
+kubectl autoscale deployment helloworld-v1 --cpu-percent=50 --min=1 --max=10
+kubectl autoscale deployment helloworld-v2 --cpu-percent=50 --min=1 --max=10
+kubectl get hpa
+```
+
+## Generate load
+
+```bash
+./loadgen.sh &
+./loadgen.sh & # run it twice to generate lots of load
+```
+
+Wait for about 2 minutes and then check the number of replicas:
+
+```bash
+kubectl get hpa
+```
+
+If the autoscaler is functioning correctly, the `REPLICAS` column should have a value > 1.
+
+## Cleanup
+
+```bash
+kubectl delete -f helloworld.yaml
+kubectl delete -f helloworld-gateway.yaml
+kubectl delete hpa helloworld-v1 helloworld-v2
+```
diff --git a/Istio-Samples/helloworld/gateway-api/README.md b/Istio-Samples/helloworld/gateway-api/README.md
new file mode 100644
index 00000000..ee37810e
--- /dev/null
+++ b/Istio-Samples/helloworld/gateway-api/README.md
@@ -0,0 +1,74 @@
+# Configure helloworld using the Kubernetes Gateway API
+
+Istio intends to make the Kubernetes [Gateway API](https://gateway-api.sigs.k8s.io/) the default API for traffic management [in the future](https://istio.io/latest/blog/2022/gateway-api-beta/).
+You can use the following instructions to configure the ingress gateway and routing for the helloworld sample.
+
+## Before you begin
+
+The Gateway API CRDs do not come installed by default on most Kubernetes clusters, so install them if not present:
+
+```bash
+kubectl get crd gateways.gateway.networking.k8s.io || \
+ { kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.5.0" | kubectl apply -f -; }
+```
+
+Also make sure you are running two versions (v1 and v2) of the helloworld service:
+
+```bash
+kubectl apply -f ../helloworld.yaml
+```
+
+## Configure the helloworld gateway
+
+Apply the helloworld gateway configuration:
+
+```bash
+kubectl apply -f ./helloworld-gateway.yaml
+```
+
+Note that unlike an Istio `Gateway`, creating a Kubernetes `Gateway` resource will, by default, also [deploy an associated controller](https://istio.io/latest/docs/tasks/traffic-management/ingress/gateway-api/#automated-deployment).
+
+Set the INGRESS_HOST environment variables to the address of the helloworld gateway:
+
+```bash
+kubectl wait --for=condition=ready gtw helloworld-gateway
+export INGRESS_HOST=$(kubectl get gtw helloworld-gateway -o jsonpath='{.status.addresses[*].value}')
+```
+
+Confirm the sample is running using curl:
+
+```bash
+for run in {1..10}; do curl http://$INGRESS_HOST/hello; done
+```
+
+Since no version routing has been configured, you should see an equal split of traffic, about half handled by helloworld-v1 and the other half handled by helloworld-v2.
+
+## Configure weight-based routing
+
+Declare the helloworld versions (Gateway API requires backend service definitions, unlike the Istio API which uses DestinationRule subsets for this):
+
+```bash
+kubectl apply -f ./helloworld-versions.yaml
+```
+
+Apply the following route rule to distribute the helloworld traffic 90% to v1, 10% to v2:
+
+```bash
+kubectl apply -f ./helloworld-route.yaml
+```
+
+Run the previous curl commands again:
+
+```bash
+for run in {1..10}; do curl http://$INGRESS_HOST/hello; done
+```
+
+Now you should see about 9 out of 10 requests handled by helloworld-v1 and only about 1 in 10 handled by helloworld-v2.
+
+## Cleanup
+
+```bash
+kubectl delete -f ./helloworld-gateway.yaml
+kubectl delete -f ./helloworld-versions.yaml
+kubectl delete -f ../helloworld.yaml
+```
diff --git a/Istio-Samples/helloworld/gateway-api/helloworld-gateway.yaml b/Istio-Samples/helloworld/gateway-api/helloworld-gateway.yaml
new file mode 100644
index 00000000..c4c8a8a6
--- /dev/null
+++ b/Istio-Samples/helloworld/gateway-api/helloworld-gateway.yaml
@@ -0,0 +1,29 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: Gateway
+metadata:
+ name: helloworld-gateway
+spec:
+ gatewayClassName: istio
+ listeners:
+ - name: http
+ port: 80
+ protocol: HTTP
+ allowedRoutes:
+ namespaces:
+ from: Same
+---
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: helloworld
+spec:
+ parentRefs:
+ - name: helloworld-gateway
+ rules:
+ - matches:
+ - path:
+ type: Exact
+ value: /hello
+ backendRefs:
+ - name: helloworld
+ port: 5000
diff --git a/Istio-Samples/helloworld/gateway-api/helloworld-route.yaml b/Istio-Samples/helloworld/gateway-api/helloworld-route.yaml
new file mode 100644
index 00000000..1e316f95
--- /dev/null
+++ b/Istio-Samples/helloworld/gateway-api/helloworld-route.yaml
@@ -0,0 +1,19 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: HTTPRoute
+metadata:
+ name: helloworld
+spec:
+ parentRefs:
+ - name: helloworld-gateway
+ rules:
+ - matches:
+ - path:
+ type: Exact
+ value: /hello
+ backendRefs:
+ - name: helloworld-v1
+ port: 5000
+ weight: 90
+ - name: helloworld-v2
+ port: 5000
+ weight: 10
diff --git a/Istio-Samples/helloworld/gateway-api/helloworld-versions.yaml b/Istio-Samples/helloworld/gateway-api/helloworld-versions.yaml
new file mode 100644
index 00000000..fc218515
--- /dev/null
+++ b/Istio-Samples/helloworld/gateway-api/helloworld-versions.yaml
@@ -0,0 +1,23 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: helloworld-v1
+spec:
+ ports:
+ - port: 5000
+ name: http
+ selector:
+ app: helloworld
+ version: v1
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: helloworld-v2
+spec:
+ ports:
+ - port: 5000
+ name: http
+ selector:
+ app: helloworld
+ version: v2
diff --git a/Istio-Samples/helloworld/gen-helloworld.sh b/Istio-Samples/helloworld/gen-helloworld.sh
new file mode 100755
index 00000000..8634ddc7
--- /dev/null
+++ b/Istio-Samples/helloworld/gen-helloworld.sh
@@ -0,0 +1,131 @@
+#!/bin/bash
+#
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -euo pipefail
+
+display_usage() {
+ echo
+ echo "USAGE: ./gen-helloworld.sh [--version] [--includeService value] [--includeDeployment value]"
+ echo " -h|--help: Prints usage information"
+ echo " --version: Specifies the version that will be returned by the helloworld service, default: 'v1'"
+ echo " --includeService: If 'true' the service will be included in the YAML, default: 'true'"
+ echo " --includeDeployment: If 'true' the deployment will be included in the YAML, default: 'true'"
+}
+
+INCLUDE_SERVICE=${INCLUDE_SERVICE:-"true"}
+INCLUDE_DEPLOYMENT=${INCLUDE_DEPLOYMENT:-"true"}
+SERVICE_VERSION=${SERVICE_VERSION:-"v1"}
+while (( "$#" )); do
+ case "$1" in
+ -h|--help)
+ display_usage
+ exit 0
+ ;;
+
+ --version)
+ SERVICE_VERSION=$2
+ shift 2
+ ;;
+
+ --includeService)
+ INCLUDE_SERVICE=$2
+ shift 2
+ ;;
+
+ --includeDeployment)
+ INCLUDE_DEPLOYMENT=$2
+ shift 2
+ ;;
+
+ *)
+ echo "Error: Unsupported flag $1" >&2
+ display_usage
+ exit 1
+ ;;
+ esac
+done
+
+SERVICE_YAML=$(cat </dev/null || true)
+if [[ "${ENVOS}" != "Linux" ]]; then
+ echo "Your system is not supported by this script. Only Linux is supported"
+ exit 1
+fi
+
+# Check prerequisites
+REQUISITES=("kubectl" "kind" "docker")
+for item in "${REQUISITES[@]}"; do
+ if [[ -z $(which "${item}") ]]; then
+ echo "${item} cannot be found on your system, please install ${item}"
+ exit 1
+ fi
+done
+
+# Function to print the usage message
+function printHelp() {
+ echo "Usage: "
+ echo " $0 --cluster-name cluster1 --k8s-release 1.22.1 --ip-space 255"
+ echo ""
+ echo "Where:"
+ echo " -n|--cluster-name - name of the k8s cluster to be created"
+ echo " -r|--k8s-release - the release of the k8s to setup, latest available if not given"
+ echo " -s|--ip-space - the 2nd to the last part for public ip addresses, 255 if not given, valid range: 0-255."
+ echo " -m|--mode - setup the required number of nodes per deployment model. Values are sidecar (1 node) or ambient (minimum of 2)"
+ echo " -w|--worker-nodes - the number of worker nodes to create. Default is 1"
+ echo " --pod-subnet - the pod subnet to specify. Default is 10.244.0.0/16 for IPv4 and fd00:10:244::/56 for IPv6"
+ echo " --service-subnet - the service subnet to specify. Default is 10.96.0.0/16 for IPv4 and fd00:10:96::/112 for IPv6"
+ echo " -i|--ip-family - ip family to be supported, default is ipv4 only. Value should be ipv4, ipv6, or dual"
+ echo " --ipv6gw - set ipv6 as the gateway, necessary for dual-stack IPv6-preferred clusters"
+ echo " -h|--help - print the usage of this script"
+}
+
+# Setup default values
+CLUSTERNAME="cluster1"
+K8SRELEASE=""
+IPSPACE=255
+IPFAMILY="ipv4"
+MODE="sidecar"
+NUMNODES=""
+PODSUBNET=""
+SERVICESUBNET=""
+IPV6GW=false
+
+# Handling parameters
+while [[ $# -gt 0 ]]; do
+ optkey="$1"
+ case $optkey in
+ -n|--cluster-name)
+ CLUSTERNAME="$2"; shift 2;;
+ -r|--k8s-release)
+ K8SRELEASE="--image=kindest/node:v$2"; shift 2;;
+ -s|--ip-space)
+ IPSPACE="$2"; shift 2;;
+ -m|--mode)
+ MODE="$2"; shift 2;;
+ -w|--worker-nodes)
+ NUMNODES="$2"; shift 2;;
+ --pod-subnet)
+ PODSUBNET="$2"; shift 2;;
+ --service-subnet)
+ SERVICESUBNET="$2"; shift 2;;
+ -i|--ip-family)
+ IPFAMILY="${2,,}";shift 2;;
+ --ipv6gw)
+ IPV6GW=true; shift;;
+ -h|--help)
+ printHelp; exit 0;;
+ *) # unknown option
+ echo "parameter $1 is not supported"; printHelp; exit 1;;
+ esac
+done
+
+# This block is to setup kind to have a local image repo to push
+# images using localhost:5000, to use this feature, start up
+# a registry container such as gcr.io/istio-testing/registry, then
+# connect it to the docker network where kind nodes are running on
+# which normally will be called kind
+FEATURES=$(cat << EOF
+featureGates:
+ MixedProtocolLBService: true
+ GRPCContainerProbe: true
+kubeadmConfigPatches:
+ - |
+ apiVersion: kubeadm.k8s.io/v1beta2
+ kind: ClusterConfiguration
+ metadata:
+ name: config
+ etcd:
+ local:
+ # Run etcd in a tmpfs (in RAM) for performance improvements
+ dataDir: /tmp/kind-cluster-etcd
+ # We run single node, drop leader election to reduce overhead
+ controllerManagerExtraArgs:
+ leader-elect: "false"
+ schedulerExtraArgs:
+ leader-elect: "false"
+ apiServer:
+ extraArgs:
+ "service-account-issuer": "kubernetes.default.svc"
+ "service-account-signing-key-file": "/etc/kubernetes/pki/sa.key"
+containerdConfigPatches:
+ - |-
+ [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5000"]
+ endpoint = ["http://kind-registry:5000"]
+EOF
+)
+
+validIPFamilies=("ipv4" "ipv6" "dual")
+# Validate if the ip family value is correct.
+isValid="false"
+for family in "${validIPFamilies[@]}"; do
+ if [[ "$family" == "${IPFAMILY}" ]]; then
+ isValid="true"
+ break
+ fi
+done
+
+if [[ "${isValid}" == "false" ]]; then
+ echo "${IPFAMILY} is not valid ip family, valid values are ipv4, ipv6 or dual"
+ exit 1
+fi
+
+if [[ "${MODE}" == "ambient" ]]; then
+ NUMNODES=${NUMNODES:-2}
+fi
+
+NODES=$(cat <<-EOM
+nodes:
+- role: control-plane
+EOM
+)
+
+if [[ -n "${NUMNODES}" ]]; then
+for _ in $(seq 1 "${NUMNODES}"); do
+ NODES+=$(printf "\n%s" "- role: worker")
+done
+fi
+
+CONFIG=$(cat <<-EOM
+kind: Cluster
+apiVersion: kind.x-k8s.io/v1alpha4
+${FEATURES}
+name: ${CLUSTERNAME}
+${NODES}
+networking:
+ ipFamily: ${IPFAMILY}
+EOM
+)
+
+if [[ -n "${PODSUBNET}" ]]; then
+ CONFIG+=$(printf "\n%s" " podSubnet: \"${PODSUBNET}\"")
+fi
+
+if [[ -n "${SERVICESUBNET}" ]]; then
+ CONFIG+=$(printf "\n%s" " serviceSubnet: \"${SERVICESUBNET}\"")
+fi
+
+# Create k8s cluster using the giving release and name
+if [[ -z "${K8SRELEASE}" ]]; then
+ cat << EOF | kind create cluster --config -
+${CONFIG}
+EOF
+else
+ cat << EOF | kind create cluster "${K8SRELEASE}" --config -
+${CONFIG}
+EOF
+fi
+
+# Setup cluster context
+kubectl cluster-info --context "kind-${CLUSTERNAME}"
+
+# Setup metallb using v0.13.11
+kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.11/config/manifests/metallb-native.yaml
+
+addrName="IPAddress"
+ipv4Prefix=""
+ipv6Prefix=""
+
+# Get both ipv4 and ipv6 gateway for the cluster
+gatewaystr=$(docker network inspect -f '{{range .IPAM.Config }}{{ .Gateway }} {{end}}' kind | cut -f1,2)
+read -r -a gateways <<< "${gatewaystr}"
+for gateway in "${gateways[@]}"; do
+ if [[ "$gateway" == *"."* ]]; then
+ ipv4Prefix=$(echo "${gateway}" |cut -d'.' -f1,2)
+ else
+ ipv6Prefix=$(echo "${gateway}" |cut -d':' -f1,2,3,4)
+ fi
+done
+
+if [[ "${IPFAMILY}" == "ipv4" ]]; then
+ addrName="IPAddress"
+ ipv4Range="- ${ipv4Prefix}.${IPSPACE}.200-${ipv4Prefix}.${IPSPACE}.240"
+ ipv6Range=""
+elif [[ "${IPFAMILY}" == "ipv6" ]]; then
+ addrName="GlobalIPv6Address"
+ ipv4Range=""
+ ipv6Range="- ${ipv6Prefix}::${IPSPACE}:200-${ipv6Prefix}::${IPSPACE}:240"
+else
+ if [[ "${IPV6GW}" == "true" ]]; then
+ addrName="GlobalIPv6Address"
+ fi
+
+ ipv4Range="- ${ipv4Prefix}.${IPSPACE}.200-${ipv4Prefix}.${IPSPACE}.240"
+ ipv6Range="- ${ipv6Prefix}::${IPSPACE}:200-${ipv6Prefix}::${IPSPACE}:240"
+fi
+
+# utility function to wait for pods to be ready
+function waitForPods() {
+ ns=$1
+ lb=$2
+ waittime=$3
+ # Wait for the pods to be ready in the given namespace with lable
+ while : ; do
+ res=$(kubectl wait --context "kind-${CLUSTERNAME}" -n "${ns}" pod \
+ -l "${lb}" --for=condition=Ready --timeout="${waittime}s" 2>/dev/null ||true)
+ if [[ "${res}" == *"condition met"* ]]; then
+ break
+ fi
+ echo "Waiting for pods in namespace ${ns} with label ${lb} to be ready..."
+ sleep "${waittime}"
+ done
+}
+
+waitForPods metallb-system app=metallb 10
+
+# Now configure the loadbalancer public IP range
+cat <&2
+ exit 1
+ ;;
+ esac
+done
+
+
+# single-cluster installations may need this gateway to allow VMs to get discovery
+# for non-single cluster, we add additional topology information
+SINGLE_CLUSTER="${SINGLE_CLUSTER:-0}"
+if [[ "${SINGLE_CLUSTER}" -eq 0 ]]; then
+ if [[ -z "${NETWORK:-}" ]]; then
+ echo "Must specify either --single-cluster or --network."
+ exit 1
+ fi
+fi
+
+# base
+IOP=$(cat < apply -f ../otel.yaml
+```
+
+In this example, we use `otel-collector` as the namespace to deploy the `otel-collector` backend:
+
+```bash
+kubectl create namespace otel-collector
+kubectl -n otel-collector apply -f ../otel.yaml
+```
+
+The otel-collector will create a grpc receiver on port `4317`, and later the sidecars will report trace information to this grpc port. You can find more details from [here](https://github.com/open-telemetry/opentelemetry-collector).
+
+Below is the configuration:
+
+```yaml
+receivers:
+ otlp:
+ protocols:
+ grpc:
+ http:
+processors:
+ batch:
+exporters:
+ logging:
+ loglevel: debug
+service:
+ pipelines:
+ logs:
+ receivers: [otlp]
+ processors: [batch]
+ exporters: [logging]
+```
+
+In this example, `Jaeger` is the exporter for gathering the traces. Assuming you have already deployed Jaeger as your tracing system with [this](https://istio.io/latest/docs/ops/integrations/jaeger/) installation, you are good to go to the next steps. If you already have your own `Jaeger` deployed, you may need to modify the otel collector config. The configmap name is `opentelemetry-collector-conf` in the namespace you deployed the otel collector, and the related config is defined as:
+
+```yaml
+exporters:
+ jaeger:
+ endpoint: jaeger-collector.istio-system.svc.cluster.local:14250
+ tls:
+ insecure: true
+ sending_queue:
+ enabled: true
+ retry_on_failure:
+ enabled: true
+service:
+ pipelines:
+ traces:
+ exporters:
+ - jaeger
+```
+
+You need to modify the jaeger exporter endpoint with the one you deployed, in this case it's `jaeger-collector.istio-system.svc.cluster.local:14250`.
+
+If you have not deployed the `Jaeger` service, you can follow [this](https://istio.io/latest/docs/ops/integrations/jaeger/) installation to install the service.
+
+You may also choose any existing tracing system if you have, and you should change the exporter settings in the configmap mentioned above.
+
+You may also choose to use your own otel collector if you have, and the key part is to have the `otlp` grpc protocol receiver to receive the traces. One important thing is to make sure your otel collector service's grpc port starts with `grpc-` prefix, which is like:
+
+```yaml
+spec:
+ ports:
+ - name: grpc-otlp
+ port: 4317
+ protocol: TCP
+ targetPort: 4317
+```
+
+Otherwise the traces may not be reported.
+
+## Update mesh config
+
+Install or update Istio with the `demo` profile to make sure you have the OpenTelemetry tracing provider enabled:
+
+```bash
+istioctl install --set profile=demo -y
+```
+
+Or ensure you have the following additional mesh config set in your Istio:
+
+```yaml
+mesh: |-
+ extensionProviders:
+ - name: otel-tracing
+ opentelemetry:
+ port: 4317
+ service: opentelemetry-collector.otel-collector.svc.cluster.local
+```
+
+Make sure the service name matches the one you deployed if you select a different namespace.
+
+## Apply the Telemetry resource to report traces
+
+Next, add a Telemetry resource that tells Istio to send trace records to the OpenTelemetry collector.
+
+```bash
+kubectl -n apply -f ./telemetry.yaml
+```
+
+In this example, we deploy it to the default namespace, which is where the sample apps
+from the [getting started](https://istio.io/latest/docs/setup/getting-started) are also deployed.
+
+```bash
+kubectl apply -f ./telemetry.yaml
+```
+
+The core config is:
+
+```yaml
+tracing:
+- providers:
+ - name: otel-tracing
+ randomSamplingPercentage: 0
+```
+
+As you see, the `randomSamplingPercentage` is 0, which means the tracing is still not enabled because of `0` sampling percentage. The tracing can be opt-on by increasing the `randomSamplingPercentage` value to `1-100`. The `Telemetry` resource can also be manipulated in workload/namespace/global levels, you can check [here](https://istio.io/latest/docs/reference/config/telemetry/) for more config examples.
+
+## Check tracing results
+
+If you have followed [this](https://istio.io/latest/docs/setup/getting-started/) getting started steps, you have the sample bookinfo applications installed. Try to make some requests to the productpage to generate some traces.
+
+Then open up the `Jaeger` dashboard with:
+
+```bash
+istioctl dashboard jaeger
+```
+
+You will see the requests' trace records.
+
+## Cleanup
+
+```bash
+kubectl -n otel-collector delete -f ./telemetry.yaml
+kubectl -n otel-collector delete -f ../otel.yaml
+```
diff --git a/Istio-Samples/open-telemetry/tracing/telemetry.yaml b/Istio-Samples/open-telemetry/tracing/telemetry.yaml
new file mode 100644
index 00000000..fd831a2b
--- /dev/null
+++ b/Istio-Samples/open-telemetry/tracing/telemetry.yaml
@@ -0,0 +1,9 @@
+apiVersion: telemetry.istio.io/v1alpha1
+kind: Telemetry
+metadata:
+ name: otel-demo
+spec:
+ tracing:
+ - providers:
+ - name: otel-tracing
+ randomSamplingPercentage: 0
diff --git a/Istio-Samples/ratelimit/local-rate-limit-service.yaml b/Istio-Samples/ratelimit/local-rate-limit-service.yaml
new file mode 100644
index 00000000..94f2299f
--- /dev/null
+++ b/Istio-Samples/ratelimit/local-rate-limit-service.yaml
@@ -0,0 +1,87 @@
+# This example shows how to use Istio local rate limiting with descriptors to limit by path.
+# This uses the base book-info demo and adds rate limiting by path, specifically rate limiting the product page
+# to 10 requests per minute, and the overall fdqn will be able to accept 100 requests per minute.
+apiVersion: networking.istio.io/v1alpha3
+kind: EnvoyFilter
+metadata:
+ name: filter-local-ratelimit-svc
+ namespace: istio-system
+spec:
+ workloadSelector:
+ labels:
+ app: productpage
+ configPatches:
+ - applyTo: HTTP_FILTER
+ match:
+ context: SIDECAR_INBOUND
+ listener:
+ filterChain:
+ filter:
+ name: "envoy.filters.network.http_connection_manager"
+ patch:
+ operation: INSERT_BEFORE
+ value:
+ name: envoy.filters.http.local_ratelimit
+ typed_config:
+ "@type": type.googleapis.com/udpa.type.v1.TypedStruct
+ type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
+ value:
+ stat_prefix: http_local_rate_limiter
+ - applyTo: HTTP_ROUTE
+ match:
+ context: SIDECAR_INBOUND
+ routeConfiguration:
+ vhost:
+ name: "inbound|http|8000"
+ route:
+ action: ANY
+ patch:
+ operation: MERGE
+ value:
+ route:
+ rate_limits:
+ - actions:
+ - remote_address: {}
+ - actions:
+ - header_value_match:
+ descriptor_value: "productpage"
+ expect_match: true
+ headers:
+ - name: :path
+ string_match:
+ prefix: /productpage
+ ignore_case: true
+
+ typed_per_filter_config:
+ envoy.filters.http.local_ratelimit:
+ "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
+ stat_prefix: test_enabled
+ token_bucket:
+ max_tokens: 100
+ tokens_per_fill: 100
+ fill_interval: 60s
+ enable_x_ratelimit_headers: DRAFT_VERSION_03 # This adds the ability to see headers for how many tokens are left in the bucket, how often the bucket refills, and what is the token bucket max.
+ filter_enabled:
+ runtime_key: test_enabled
+ default_value:
+ numerator: 100
+ denominator: HUNDRED
+ filter_enforced:
+ runtime_key: test_enabled
+ default_value:
+ numerator: 100
+ denominator: HUNDRED
+ response_headers_to_add:
+ - append: false
+ header:
+ key: x-local-rate-limit
+ value: "true"
+ descriptors:
+ - entries:
+ - key: header_match
+ value: productpage
+ token_bucket:
+ max_tokens: 10
+ tokens_per_fill: 10
+ fill_interval: 60s
+
diff --git a/Istio-Samples/ratelimit/rate-limit-service.yaml b/Istio-Samples/ratelimit/rate-limit-service.yaml
new file mode 100644
index 00000000..cfda9c76
--- /dev/null
+++ b/Istio-Samples/ratelimit/rate-limit-service.yaml
@@ -0,0 +1,151 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Redis service and deployment
+# Ratelimit service and deployment
+
+# Note: a configmap is needed to make the rate limit deployment work properly, for example:
+#
+# apiVersion: v1
+# kind: ConfigMap
+# metadata:
+# name: ratelimit-config
+# data:
+# config.yaml: |
+# domain: echo-ratelimit
+# descriptors:
+# - key: PATH
+# value: "/"
+# rate_limit:
+# unit: minute
+# requests_per_unit: 1
+# - key: PATH
+# rate_limit:
+# unit: minute
+# requests_per_unit: 100
+##################################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: redis
+ labels:
+ app: redis
+spec:
+ ports:
+ - name: redis
+ port: 6379
+ selector:
+ app: redis
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: redis
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: redis
+ template:
+ metadata:
+ labels:
+ app: redis
+ spec:
+ containers:
+ - image: redis:alpine
+ imagePullPolicy: Always
+ name: redis
+ ports:
+ - name: redis
+ containerPort: 6379
+ restartPolicy: Always
+ serviceAccountName: ""
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: ratelimit
+ labels:
+ app: ratelimit
+spec:
+ ports:
+ - name: http-port
+ port: 8080
+ targetPort: 8080
+ protocol: TCP
+ - name: grpc-port
+ port: 8081
+ targetPort: 8081
+ protocol: TCP
+ - name: http-debug
+ port: 6070
+ targetPort: 6070
+ protocol: TCP
+ selector:
+ app: ratelimit
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: ratelimit
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: ratelimit
+ strategy:
+ type: Recreate
+ template:
+ metadata:
+ labels:
+ app: ratelimit
+ spec:
+ containers:
+ - image: envoyproxy/ratelimit:9d8d70a8 # 2022/08/16
+ imagePullPolicy: Always
+ name: ratelimit
+ command: ["/bin/ratelimit"]
+ env:
+ - name: LOG_LEVEL
+ value: debug
+ - name: REDIS_SOCKET_TYPE
+ value: tcp
+ - name: REDIS_URL
+ value: redis:6379
+ - name: USE_STATSD
+ value: "false"
+ - name: RUNTIME_ROOT
+ value: /data
+ - name: RUNTIME_SUBDIRECTORY
+ value: ratelimit
+ - name: RUNTIME_WATCH_ROOT
+ value: "false"
+ - name: RUNTIME_IGNOREDOTFILES
+ value: "true"
+ - name: HOST
+ value: "::"
+ - name: GRPC_HOST
+ value: "::"
+ ports:
+ - containerPort: 8080
+ - containerPort: 8081
+ - containerPort: 6070
+ volumeMounts:
+ - name: config-volume
+ mountPath: /data/ratelimit/config
+ volumes:
+ - name: config-volume
+ configMap:
+ name: ratelimit-config
diff --git a/Istio-Samples/security/psp/sidecar-psp.yaml b/Istio-Samples/security/psp/sidecar-psp.yaml
new file mode 100644
index 00000000..b44748f1
--- /dev/null
+++ b/Istio-Samples/security/psp/sidecar-psp.yaml
@@ -0,0 +1,46 @@
+apiVersion: policy/v1
+kind: PodSecurityPolicy
+metadata:
+ name: istio-sidecar
+spec:
+ # Allow the istio sidecar injector to work
+ allowedCapabilities:
+ - NET_ADMIN
+ - NET_RAW
+ seLinux:
+ rule: RunAsAny
+ supplementalGroups:
+ rule: RunAsAny
+ runAsUser:
+ rule: RunAsAny
+ fsGroup:
+ rule: RunAsAny
+ volumes:
+ - '*'
+---
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: istio-sidecar-psp
+rules:
+ - apiGroups:
+ - extensions
+ resources:
+ - podsecuritypolicies
+ resourceNames:
+ - istio-sidecar
+ verbs:
+ - use
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: istio-sidecar-psp
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: istio-sidecar-psp
+subjects:
+ - apiGroup: rbac.authorization.k8s.io
+ kind: Group
+ name: system:serviceaccounts
diff --git a/Istio-Samples/security/spire/README.md b/Istio-Samples/security/spire/README.md
new file mode 100644
index 00000000..b3e1978f
--- /dev/null
+++ b/Istio-Samples/security/spire/README.md
@@ -0,0 +1,90 @@
+# Integrating SPIRE as a CA through Envoy's SDS API
+
+This sample deploys a setup of [SPIRE](https://github.com/spiffe/spire) (the SPIFFE Runtime Environment) as an example of integrating with [Envoy's SDS](https://www.envoyproxy.io/docs/envoy/latest/configuration/security/secret) API. For more information
+on the SPIFFE specs, refer to the [SPIFFE Overview](https://spiffe.io/docs/latest/spiffe-about/overview/).
+
+Once SPIRE is deployed and integrated with Istio, this sample deploys a modified version of the [sleep](/samples/sleep/README.md) service and validates that its [identity](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/#spiffe-verifiable-identity-document-svid) was issued by SPIRE. Workload registration is handled by the [SPIRE Controller Manager](https://github.com/spiffe/spire-controller-manager).
+
+See [Istio CA Integration with SPIRE](https://istio.io/latest/docs/ops/integrations/spire) for further details about this integration.
+
+## Deploy the integration
+
+1. Deploy SPIRE. For proper socket injection, this **must** be done prior to installing Istio in your cluster:
+
+ ```bash
+ $ kubectl apply -f spire-quickstart.yaml
+ ```
+
+1. Ensure that the deployment is completed before moving to the next step. This can be verified by waiting on the `spire-agent` pod to become ready:
+
+ ```bash
+ $ kubectl wait pod --for=condition=ready -n spire -l app=spire-agent
+ ```
+
+1. Use the configuration profile provided to install Istio (requires istioctl v1.14+):
+
+ ```bash
+ $ istioctl install -f istio-spire-config.yaml
+ ```
+
+1. Create a ClusterSPIFFEID to create a registration entry for all workloads with the `spiffe.io/spire-managed-identity: true` label:
+
+ ```bash
+ $ kubectl apply -f clusterspiffeid.yaml
+ ```
+
+1. Add the `spiffe.io/spire-managed-identity: true` label to the Ingress-gateway Deployment:
+
+ ```bash
+ $ kubectl patch deployment istio-ingressgateway -n istio-system -p '{"spec":{"template":{"metadata":{"labels":{"spiffe.io/spire-managed-identity": "true"}}}}}'
+ ```
+
+1. Deploy the `sleep-spire.yaml` version of the [sleep](/samples/sleep/README.md) service, which injects the custom istio-agent template defined in `istio-spire-config.yaml` and has the `spiffe.io/spire-managed-identity: true` label.
+
+ If you have [automatic sidecar injection](https://istio.io/docs/setup/additional-setup/sidecar-injection/#automatic-sidecar-injection) enabled:
+
+ ```bash
+ $ kubectl apply -f sleep-spire.yaml
+ ```
+
+ Otherwise, manually inject the sidecar before applying:
+
+ ```bash
+ $ kubectl apply -f <(istioctl kube-inject -f sleep-spire.yaml)
+ ```
+
+1. Retrieve sleep's SVID identity document using the `istioctl proxy-config secret` command:
+
+ ```bash
+ $ export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath="{.items[0].metadata.name}")
+ $ istioctl pc secret $SLEEP_POD -o json | jq -r \
+ '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' | base64 --decode > chain.pem
+ ```
+
+1. Inspect the certificate content and verify that SPIRE was the issuer:
+
+ ```bash
+ $ openssl x509 -in chain.pem -text | grep SPIRE
+ Subject: C = US, O = SPIRE, CN = sleep-5d6df95bbf-kt2tt
+ ```
+
+## Tear down
+
+1. Delete all deployments and configurations for the SPIRE Agent, Server, and namespace:
+
+ ```bash
+ $ kubectl delete namespace spire
+ ```
+
+1. Delete the ClusterRole, ClusterRoleBinding, Role, RoleBindings, ValidatingWebhookConfiguration, CSIDriver, and CustomResourceDefinition:
+
+ ```bash
+ $ kubectl delete clusterrole spire-server-cluster-role spire-agent-cluster-role manager-role
+ $ kubectl delete clusterrolebinding spire-server-cluster-role-binding spire-agent-cluster-role-binding manager-role-binding
+ $ kubectl delete role spire-server-role leader-election-role
+ $ kubectl delete rolebinding spire-server-role-binding leader-election-role-binding
+ $ kubectl delete ValidatingWebhookConfiguration spire-controller-manager-webhook
+ $ kubectl delete csidriver csi.spiffe.io
+ $ kubectl delete CustomResourceDefinition clusterspiffeids.spire.spiffe.io
+ $ kubectl delete CustomResourceDefinition clusterfederatedtrustdomains.spire.spiffe.io
+ ```
diff --git a/Istio-Samples/security/spire/clusterspiffeid.yaml b/Istio-Samples/security/spire/clusterspiffeid.yaml
new file mode 100644
index 00000000..bf67989e
--- /dev/null
+++ b/Istio-Samples/security/spire/clusterspiffeid.yaml
@@ -0,0 +1,9 @@
+apiVersion: spire.spiffe.io/v1alpha1
+kind: ClusterSPIFFEID
+metadata:
+ name: example
+spec:
+ spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
+ podSelector:
+ matchLabels:
+ spiffe.io/spire-managed-identity: "true"
diff --git a/Istio-Samples/security/spire/istio-spire-config.yaml b/Istio-Samples/security/spire/istio-spire-config.yaml
new file mode 100644
index 00000000..812c65ec
--- /dev/null
+++ b/Istio-Samples/security/spire/istio-spire-config.yaml
@@ -0,0 +1,70 @@
+apiVersion: install.istio.io/v1alpha1
+kind: IstioOperator
+metadata:
+ namespace: istio-system
+spec:
+ profile: default
+ meshConfig:
+ trustDomain: example.org
+ values:
+ global:
+ # This is used to customize the sidecar template
+ sidecarInjectorWebhook:
+ templates:
+ spire: |
+ spec:
+ containers:
+ - name: istio-proxy
+ volumeMounts:
+ - name: workload-socket
+ mountPath: /run/secrets/workload-spiffe-uds
+ readOnly: true
+ volumes:
+ - name: workload-socket
+ csi:
+ driver: "csi.spiffe.io"
+ readOnly: true
+ components:
+ ingressGateways:
+ - name: istio-ingressgateway
+ enabled: true
+ label:
+ istio: ingressgateway
+ k8s:
+ overlays:
+ - apiVersion: apps/v1
+ kind: Deployment
+ name: istio-ingressgateway
+ patches:
+ - path: spec.template.spec.volumes.[name:workload-socket]
+ value:
+ name: workload-socket
+ csi:
+ driver: "csi.spiffe.io"
+ readOnly: true
+ - path: spec.template.spec.containers.[name:istio-proxy].volumeMounts.[name:workload-socket]
+ value:
+ name: workload-socket
+ mountPath: "/run/secrets/workload-spiffe-uds"
+ readOnly: true
+ - path: spec.template.spec.initContainers
+ value:
+ - name: wait-for-spire-socket
+ image: busybox:1.28
+ volumeMounts:
+ - name: workload-socket
+ mountPath: /run/secrets/workload-spiffe-uds
+ readOnly: true
+ env:
+ - name: CHECK_FILE
+ value: /run/secrets/workload-spiffe-uds/socket
+ command:
+ - sh
+ - "-c"
+ - |-
+ echo `date -Iseconds` Waiting for: ${CHECK_FILE}
+ while [[ ! -e ${CHECK_FILE} ]] ; do
+ echo `date -Iseconds` File does not exist: ${CHECK_FILE}
+ sleep 15
+ done
+ ls -l ${CHECK_FILE}
diff --git a/Istio-Samples/security/spire/sleep-spire.yaml b/Istio-Samples/security/spire/sleep-spire.yaml
new file mode 100644
index 00000000..d1e1673f
--- /dev/null
+++ b/Istio-Samples/security/spire/sleep-spire.yaml
@@ -0,0 +1,70 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Sleep service
+##################################################################################################
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: sleep
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: sleep
+ labels:
+ app: sleep
+ service: sleep
+spec:
+ ports:
+ - port: 80
+ name: http
+ selector:
+ app: sleep
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: sleep
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: sleep
+ template:
+ metadata:
+ labels:
+ app: sleep
+ spiffe.io/spire-managed-identity: "true"
+ # Injects custom sidecar template
+ annotations:
+ inject.istio.io/templates: "sidecar,spire"
+ spec:
+ terminationGracePeriodSeconds: 0
+ serviceAccountName: sleep
+ containers:
+ - name: sleep
+ image: curlimages/curl
+ command: ["/bin/sleep", "infinity"]
+ imagePullPolicy: IfNotPresent
+ volumeMounts:
+ - name: tmp
+ mountPath: /tmp
+ securityContext:
+ runAsUser: 1000
+ volumes:
+ - name: tmp
+ emptyDir: {}
+---
\ No newline at end of file
diff --git a/Istio-Samples/security/spire/spire-quickstart.yaml b/Istio-Samples/security/spire/spire-quickstart.yaml
new file mode 100644
index 00000000..238c91b6
--- /dev/null
+++ b/Istio-Samples/security/spire/spire-quickstart.yaml
@@ -0,0 +1,985 @@
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: spire
+
+---
+apiVersion: storage.k8s.io/v1
+kind: CSIDriver
+metadata:
+ name: "csi.spiffe.io"
+spec:
+ # Only ephemeral, inline volumes are supported. There is no need for a
+ # controller to provision and attach volumes.
+ attachRequired: false
+
+ # Request the pod information which the CSI driver uses to verify that an
+ # ephemeral mount was requested.
+ podInfoOnMount: true
+
+ # Don't change ownership on the contents of the mount since the Workload API
+ # Unix Domain Socket is typically open to all (i.e. 0777).
+ fsGroupPolicy: None
+
+ # Declare support for ephemeral volumes only.
+ volumeLifecycleModes:
+ - Ephemeral
+
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: spire-server
+ namespace: spire
+
+---
+# ConfigMap for spire-agent bootstrapping.
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: spire-bundle
+ namespace: spire
+
+---
+# ClusterRole to allow spire-server to query k8s API server.
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: spire-server-cluster-role
+rules:
+ # allow TokenReview requests (to verify service account tokens for PSAT
+ # attestation)
+- apiGroups: ["authentication.k8s.io"]
+ resources: ["tokenreviews"]
+ verbs: ["get", "create"]
+- apiGroups: [""]
+ resources: ["nodes"]
+ verbs: ["get"]
+
+---
+# Binds above cluster role to spire-server service account.
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: spire-server-cluster-role-binding
+subjects:
+- kind: ServiceAccount
+ name: spire-server
+ namespace: spire
+roleRef:
+ kind: ClusterRole
+ name: spire-server-cluster-role
+ apiGroup: rbac.authorization.k8s.io
+
+---
+# Role for the SPIRE server.
+kind: Role
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ namespace: spire
+ name: spire-server-role
+rules:
+ # allow "get" access to pods (to resolve selectors for PSAT attestation)
+- apiGroups: [""]
+ resources: ["pods"]
+ verbs: ["get"]
+ # allow access to "get" and "patch" the spire-bundle ConfigMap (for SPIRE
+ # agent bootstrapping, see the spire-bundle ConfigMap)
+- apiGroups: [""]
+ resources: ["configmaps"]
+ resourceNames: ["spire-bundle"]
+ verbs: ["get", "patch"]
+
+---
+# RoleBinding granting the spire-server-role to the SPIRE server
+# service account.
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: spire-server-role-binding
+ namespace: spire
+subjects:
+- kind: ServiceAccount
+ name: spire-server
+ namespace: spire
+roleRef:
+ kind: Role
+ name: spire-server-role
+ apiGroup: rbac.authorization.k8s.io
+
+---
+# ClusterRules for the SPIRE Controller Manager.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: manager-role
+rules:
+ - apiGroups: [""]
+ resources: ["namespaces"]
+ verbs: ["get", "list", "watch"]
+ - apiGroups: ["admissionregistration.k8s.io"]
+ resources: ["validatingwebhookconfigurations"]
+ verbs: ["get", "list", "patch", "watch"]
+ - apiGroups: [""]
+ resources: ["nodes"]
+ verbs: ["get", "list", "watch"]
+ - apiGroups: [""]
+ resources: ["pods"]
+ verbs: ["get", "list", "watch"]
+ - apiGroups: ["spire.spiffe.io"]
+ resources: ["clusterfederatedtrustdomains"]
+ verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
+ - apiGroups: ["spire.spiffe.io"]
+ resources: ["clusterfederatedtrustdomains/finalizers"]
+ verbs: ["update"]
+ - apiGroups: ["spire.spiffe.io"]
+ resources: ["clusterfederatedtrustdomains/status"]
+ verbs: ["get", "patch", "update"]
+ - apiGroups: ["spire.spiffe.io"]
+ resources: ["clusterspiffeids"]
+ verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
+ - apiGroups: ["spire.spiffe.io"]
+ resources: ["clusterspiffeids/finalizers"]
+ verbs: ["update"]
+ - apiGroups: ["spire.spiffe.io"]
+ resources: ["clusterspiffeids/status"]
+ verbs: ["get", "patch", "update"]
+
+---
+# Binds manager-role cluster role to spire-server service account.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: manager-role-binding
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: manager-role
+subjects:
+- kind: ServiceAccount
+ name: spire-server
+ namespace: spire
+
+---
+# Permissions for the SPIRE server to do leader election.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: leader-election-role
+ namespace: spire
+rules:
+ - apiGroups: [""]
+ resources: ["configmaps"]
+ verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
+ - apiGroups: ["coordination.k8s.io"]
+ resources: ["leases"]
+ verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
+ - apiGroups: [""]
+ resources: ["events"]
+ verbs: ["create", "patch"]
+
+---
+# Binds leader-election-role to spire-server service account.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: leader-election-role-binding
+ namespace: spire
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: leader-election-role
+subjects:
+- kind: ServiceAccount
+ name: spire-server
+ namespace: spire
+
+---
+# ConfigMap containing the SPIRE server configuration.
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: spire-server
+ namespace: spire
+data:
+ server.conf: |
+ server {
+ bind_address = "0.0.0.0"
+ bind_port = "8081"
+ trust_domain = "example.org"
+ data_dir = "/run/spire/server/data"
+ log_level = "DEBUG"
+ federation {
+ bundle_endpoint {
+ address = "0.0.0.0"
+ port = 8443
+ }
+ }
+ }
+
+ plugins {
+ DataStore "sql" {
+ plugin_data {
+ database_type = "sqlite3"
+ connection_string = "/run/spire/server/data/datastore.sqlite3"
+ }
+ }
+
+ NodeAttestor "k8s_psat" {
+ plugin_data {
+ clusters = {
+ # NOTE: Change this to your cluster name
+ "demo-cluster" = {
+ service_account_allow_list = ["spire:spire-agent"]
+ }
+ }
+ }
+ }
+
+ KeyManager "disk" {
+ plugin_data {
+ keys_path = "/run/spire/server/data/keys.json"
+ }
+ }
+
+ Notifier "k8sbundle" {
+ plugin_data {
+ namespace = "spire"
+ }
+ }
+ }
+
+ health_checks {
+ listener_enabled = true
+ bind_address = "0.0.0.0"
+ bind_port = "8080"
+ live_path = "/live"
+ ready_path = "/ready"
+ }
+
+---
+# Configuration for the SPIRE Controller Manager.
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: spire-controller-manager-config
+ namespace: spire
+data:
+ spire-controller-manager-config.yaml: |
+ apiVersion: spire.spiffe.io/v1alpha1
+ kind: ControllerManagerConfig
+ metrics:
+ bindAddress: 127.0.0.1:8082
+ healthProbe:
+ bindAddress: 127.0.0.1:8083
+ leaderElection:
+ leaderElect: true
+ resourceName: 98c9c988.spiffe.io
+ resourceNamespace: spire
+ clusterName: demo-cluster
+ trustDomain: example.org
+ ignoreNamespaces:
+ - kube-system
+ - kube-public
+ - spire
+ - local-path-storage
+
+---
+# SPIRE Server Deployment.
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: spire-server
+ namespace: spire
+ labels:
+ app: spire-server
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: spire-server
+ template:
+ metadata:
+ namespace: spire
+ labels:
+ app: spire-server
+ spec:
+ serviceAccountName: spire-server
+ shareProcessNamespace: true
+ containers:
+ - name: spire-server
+ image: ghcr.io/spiffe/spire-server:1.5.4
+ imagePullPolicy: IfNotPresent
+ args:
+ - -config
+ - /run/spire/server/config/server.conf
+ livenessProbe:
+ httpGet:
+ path: /live
+ port: 8080
+ failureThreshold: 2
+ initialDelaySeconds: 15
+ periodSeconds: 60
+ timeoutSeconds: 3
+ readinessProbe:
+ httpGet:
+ path: /ready
+ port: 8080
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ ports:
+ - containerPort: 8081
+ volumeMounts:
+ - name: spire-config
+ mountPath: /run/spire/server/config
+ readOnly: true
+ - name: spire-server-socket
+ mountPath: /tmp/spire-server/private
+ readOnly: false
+ - name: spire-controller-manager
+ image: ghcr.io/spiffe/spire-controller-manager:0.2.3
+ imagePullPolicy: IfNotPresent
+ args:
+ - "--config=spire-controller-manager-config.yaml"
+ ports:
+ - containerPort: 9443
+ volumeMounts:
+ - name: spire-server-socket
+ mountPath: /spire-server
+ readOnly: true
+ - name: spire-controller-manager-config
+ mountPath: /spire-controller-manager-config.yaml
+ subPath: spire-controller-manager-config.yaml
+ volumes:
+ - name: spire-config
+ configMap:
+ name: spire-server
+ - name: spire-server-socket
+ emptyDir: {}
+ - name: spire-controller-manager-config
+ configMap:
+ name: spire-controller-manager-config
+
+---
+# Service definition for SPIRE server defining the gRPC port.
+apiVersion: v1
+kind: Service
+metadata:
+ name: spire-server
+ namespace: spire
+spec:
+ type: NodePort
+ ports:
+ - name: grpc
+ port: 8081
+ targetPort: 8081
+ protocol: TCP
+ selector:
+ app: spire-server
+
+---
+# Service definition for SPIRE server bundle endpoint.
+apiVersion: v1
+kind: Service
+metadata:
+ name: spire-server-bundle-endpoint
+ namespace: spire
+spec:
+ type: NodePort
+ ports:
+ - name: tcp-api
+ port: 8443
+ protocol: TCP
+ selector:
+ app: spire-server
+
+---
+# Service definition for SPIRE controller manager webhook.
+apiVersion: v1
+kind: Service
+metadata:
+ name: spire-controller-manager-webhook-service
+ namespace: spire
+spec:
+ ports:
+ - name: tcp
+ port: 443
+ protocol: TCP
+ targetPort: 9443
+ selector:
+ app: spire-server
+
+---
+# ClusterFederatedTrustDomains CRD.
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.8.0
+ creationTimestamp: null
+ name: clusterfederatedtrustdomains.spire.spiffe.io
+spec:
+ group: spire.spiffe.io
+ names:
+ kind: ClusterFederatedTrustDomain
+ listKind: ClusterFederatedTrustDomainList
+ plural: clusterfederatedtrustdomains
+ singular: clusterfederatedtrustdomain
+ scope: Cluster
+ versions:
+ - additionalPrinterColumns:
+ - jsonPath: .spec.trustDomain
+ name: Trust Domain
+ type: string
+ - jsonPath: .spec.bundleEndpointURL
+ name: Endpoint URL
+ type: string
+ name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: ClusterFederatedTrustDomain is the Schema for the clusterfederatedtrustdomains
+ 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: ClusterFederatedTrustDomainSpec defines the desired state
+ of ClusterFederatedTrustDomain
+ properties:
+ bundleEndpointProfile:
+ description: BundleEndpointProfile is the profile for the bundle endpoint.
+ properties:
+ endpointSPIFFEID:
+ description: EndpointSPIFFEID is the SPIFFE ID of the bundle endpoint.
+ It is required for the "https_spiffe" profile.
+ type: string
+ type:
+ description: Type is the type of the bundle endpoint profile.
+ enum:
+ - https_spiffe
+ - https_web
+ type: string
+ required:
+ - type
+ type: object
+ bundleEndpointURL:
+ description: BundleEndpointURL is the URL of the bundle endpoint.
+ It must be an HTTPS URL and cannot contain userinfo (i.e. username/password).
+ type: string
+ trustDomain:
+ description: TrustDomain is the name of the trust domain to federate
+ with (e.g. example.org)
+ pattern: '[a-z0-9._-]{1,255}'
+ type: string
+ trustDomainBundle:
+ description: TrustDomainBundle is the contents of the bundle for the
+ referenced trust domain. This field is optional when the resource
+ is created.
+ type: string
+ required:
+ - bundleEndpointProfile
+ - bundleEndpointURL
+ - trustDomain
+ type: object
+ status:
+ description: ClusterFederatedTrustDomainStatus defines the observed state
+ of ClusterFederatedTrustDomain
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
+
+---
+# ClusterSPIFFEID CRD.
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.8.0
+ creationTimestamp: null
+ name: clusterspiffeids.spire.spiffe.io
+spec:
+ group: spire.spiffe.io
+ names:
+ kind: ClusterSPIFFEID
+ listKind: ClusterSPIFFEIDList
+ plural: clusterspiffeids
+ singular: clusterspiffeid
+ scope: Cluster
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: ClusterSPIFFEID is the Schema for the clusterspiffeids 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: ClusterSPIFFEIDSpec defines the desired state of ClusterSPIFFEID
+ properties:
+ admin:
+ description: Admin indicates whether or not the SVID can be used to
+ access the SPIRE administrative APIs. Extra care should be taken
+ to only apply this SPIFFE ID to admin workloads.
+ type: boolean
+ dnsNameTemplates:
+ description: DNSNameTemplate represents templates for extra DNS names
+ that are applicable to SVIDs minted for this ClusterSPIFFEID. The
+ node and pod spec are made available to the template under .NodeSpec,
+ .PodSpec respectively.
+ items:
+ type: string
+ type: array
+ downstream:
+ description: Downstream indicates that the entry describes a downstream SPIRE server.
+ type: boolean
+ federatesWith:
+ description: FederatesWith is a list of trust domain names that workloads
+ that obtain this SPIFFE ID will federate with.
+ items:
+ type: string
+ type: array
+ namespaceSelector:
+ description: NamespaceSelector selects the namespaces that are targeted
+ by this CRD.
+ 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
+ podSelector:
+ description: PodSelector selects the pods that are targeted by this
+ CRD.
+ 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
+ spiffeIDTemplate:
+ description: SPIFFEID is the SPIFFE ID template. The node and pod
+ spec are made available to the template under .NodeSpec, .PodSpec
+ respectively.
+ type: string
+ ttl:
+ description: TTL indicates an upper-bound time-to-live for SVIDs minted
+ for this ClusterSPIFFEID. If unset, a default will be chosen.
+ type: string
+ workloadSelectorTemplates:
+ description: WorkloadSelectorTemplates are templates to produce arbitrary
+ workload selectors that apply to a given workload before it will
+ receive this SPIFFE ID. The rendered value is interpreted by SPIRE
+ and are of the form type:value, where the value may, and often does,
+ contain semicolons, .e.g., k8s:container-image:docker/hello-world
+ The node and pod spec are made available to the template under .NodeSpec,
+ .PodSpec respectively.
+ items:
+ type: string
+ type: array
+ required:
+ - spiffeIDTemplate
+ type: object
+ status:
+ description: ClusterSPIFFEIDStatus defines the observed state of ClusterSPIFFEID
+ properties:
+ stats:
+ description: Stats produced by the last entry reconciliation run
+ properties:
+ entriesMasked:
+ description: How many entries were masked by entries for other
+ ClusterSPIFFEIDs. This happens when one or more ClusterSPIFFEIDs
+ produce an entry for the same pod with the same set of workload
+ selectors.
+ type: integer
+ entriesToSet:
+ description: How many entries are to be set for this ClusterSPIFFEID.
+ In nominal conditions, this should reflect the number of pods
+ selected, but not always if there were problems encountered
+ rendering an entry for the pod (RenderFailures) or entries are
+ masked (EntriesMasked).
+ type: integer
+ entryFailures:
+ description: How many entries were unable to be set due to failures
+ to create or update the entries via the SPIRE Server API.
+ type: integer
+ namespacesIgnored:
+ description: How many (selected) namespaces were ignored (based
+ on configuration).
+ type: integer
+ namespacesSelected:
+ description: How many namespaces were selected.
+ type: integer
+ podEntryRenderFailures:
+ description: How many failures were encountered rendering an entry
+ selected pods. This could be due to either a bad template in
+ the ClusterSPIFFEID or Pod metadata that when applied to the
+ template did not produce valid entry values.
+ type: integer
+ podsSelected:
+ description: How many pods were selected out of the namespaces.
+ type: integer
+ type: object
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
+
+---
+# ValidatingWebhookConfiguration for validating ClusterSPIFFEID and
+# ClusterFederatedTrustDomain custom resources.
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+ name: spire-controller-manager-webhook
+webhooks:
+ - admissionReviewVersions: ["v1"]
+ clientConfig:
+ service:
+ name: spire-controller-manager-webhook-service
+ namespace: spire
+ path: /validate-spire-spiffe-io-v1alpha1-clusterfederatedtrustdomain
+ failurePolicy: Fail
+ name: vclusterfederatedtrustdomain.kb.io
+ rules:
+ - apiGroups: ["spire.spiffe.io"]
+ apiVersions: ["v1alpha1"]
+ operations: ["CREATE", "UPDATE"]
+ resources: ["clusterfederatedtrustdomains"]
+ sideEffects: None
+ - admissionReviewVersions: ["v1"]
+ clientConfig:
+ service:
+ name: spire-controller-manager-webhook-service
+ namespace: spire
+ path: /validate-spire-spiffe-io-v1alpha1-clusterspiffeid
+ failurePolicy: Fail
+ name: vclusterspiffeid.kb.io
+ rules:
+ - apiGroups: ["spire.spiffe.io"]
+ apiVersions: ["v1alpha1"]
+ operations: ["CREATE", "UPDATE"]
+ resources: ["clusterspiffeids"]
+ sideEffects: None
+
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: spire-agent
+ namespace: spire
+
+---
+# Required cluster role to allow spire-agent to query k8s API server.
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: spire-agent-cluster-role
+rules:
+- apiGroups: [""]
+ resources: ["pods","nodes","nodes/proxy"]
+ verbs: ["get"]
+
+---
+# Binds above cluster role to spire-agent service account.
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: spire-agent-cluster-role-binding
+subjects:
+- kind: ServiceAccount
+ name: spire-agent
+ namespace: spire
+roleRef:
+ kind: ClusterRole
+ name: spire-agent-cluster-role
+ apiGroup: rbac.authorization.k8s.io
+
+---
+# ConfigMap for the SPIRE agent featuring:
+# 1) PSAT node attestation
+# 2) K8S Workload Attestation over the secure kubelet port
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: spire-agent
+ namespace: spire
+data:
+ agent.conf: |
+ agent {
+ data_dir = "/run/spire"
+ log_level = "DEBUG"
+ server_address = "spire-server"
+ server_port = "8081"
+ socket_path = "/run/secrets/workload-spiffe-uds/socket"
+ trust_bundle_path = "/run/spire/bundle/bundle.crt"
+ trust_domain = "example.org"
+ }
+
+ plugins {
+ NodeAttestor "k8s_psat" {
+ plugin_data {
+ # NOTE: Change this to your cluster name
+ cluster = "demo-cluster"
+ }
+ }
+
+ KeyManager "memory" {
+ plugin_data {
+ }
+ }
+
+ WorkloadAttestor "k8s" {
+ plugin_data {
+ # Defaults to the secure kubelet port by default.
+ # Minikube does not have a cert in the cluster CA bundle that
+ # can authenticate the kubelet cert, so skip validation.
+ skip_kubelet_verification = true
+
+ # We need to set disable_container_selectors = true if we make holdApplicationUntilProxyStarts = true in istio
+ # see https://istio.io/latest/docs/reference/config/istio.mesh.v1alpha1/#ProxyConfig
+ # If true, container selectors are not produced.
+ # This can be used to produce pod selectors when the workload pod is known
+ # but the workload container is not ready at the time of attestation.
+ # disable_container_selectors = true
+ }
+ }
+
+ WorkloadAttestor "unix" {
+ plugin_data {
+ }
+ }
+
+ }
+
+---
+# SPIRE Agent DaemonSet.
+apiVersion: apps/v1
+kind: DaemonSet
+metadata:
+ name: spire-agent
+ namespace: spire
+ labels:
+ app: spire-agent
+spec:
+ selector:
+ matchLabels:
+ app: spire-agent
+ template:
+ metadata:
+ namespace: spire
+ labels:
+ app: spire-agent
+ spec:
+ hostPID: true
+ hostNetwork: true
+ dnsPolicy: ClusterFirstWithHostNet
+ serviceAccountName: spire-agent
+ containers:
+ - name: spire-agent
+ image: ghcr.io/spiffe/spire-agent:1.5.4
+ imagePullPolicy: IfNotPresent
+ args: ["-config", "/run/spire/config/agent.conf"]
+ volumeMounts:
+ - name: spire-config
+ mountPath: /run/spire/config
+ readOnly: true
+ - name: spire-bundle
+ mountPath: /run/spire/bundle
+ readOnly: true
+ - name: spire-agent-socket-dir
+ mountPath: /run/secrets/workload-spiffe-uds
+ - name: spire-token
+ mountPath: /var/run/secrets/tokens
+ # This is the container which runs the SPIFFE CSI driver.
+ - name: spiffe-csi-driver
+ image: ghcr.io/spiffe/spiffe-csi-driver:0.2.0
+ imagePullPolicy: IfNotPresent
+ args: [
+ "-workload-api-socket-dir", "/spire-agent-socket",
+ "-csi-socket-path", "/spiffe-csi/csi.sock",
+ ]
+ env:
+ # The CSI driver needs a unique node ID. The node name can be
+ # used for this purpose.
+ - name: MY_NODE_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: spec.nodeName
+ volumeMounts:
+ # The volume containing the SPIRE agent socket. The SPIFFE CSI
+ # driver will mount this directory into containers.
+ - mountPath: /spire-agent-socket
+ name: spire-agent-socket-dir
+ readOnly: true
+ # The volume that will contain the CSI driver socket shared
+ # with the kubelet and the driver registrar.
+ - mountPath: /spiffe-csi
+ name: spiffe-csi-socket-dir
+ # The volume containing mount points for containers.
+ - mountPath: /var/lib/kubelet/pods
+ mountPropagation: Bidirectional
+ name: mountpoint-dir
+ securityContext:
+ privileged: true
+ # This container runs the CSI Node Driver Registrar which takes care
+ # of all the little details required to register a CSI driver with
+ # the kubelet.
+ - name: node-driver-registrar
+ image: registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.4.0
+ imagePullPolicy: IfNotPresent
+ args: [
+ "-csi-address", "/spiffe-csi/csi.sock",
+ "-kubelet-registration-path", "/var/lib/kubelet/plugins/csi.spiffe.io/csi.sock",
+ ]
+ volumeMounts:
+ # The registrar needs access to the SPIFFE CSI driver socket
+ - mountPath: /spiffe-csi
+ name: spiffe-csi-socket-dir
+ # The registrar needs access to the Kubelet plugin registration
+ # directory
+ - name: kubelet-plugin-registration-dir
+ mountPath: /registration
+ volumes:
+ - name: spire-config
+ configMap:
+ name: spire-agent
+ - name: spire-bundle
+ configMap:
+ name: spire-bundle
+ - name: spire-token
+ projected:
+ sources:
+ - serviceAccountToken:
+ path: spire-agent
+ expirationSeconds: 7200
+ audience: spire-server
+ # This volume is used to share the workload api socket between the
+ # CSI driver and SPIRE agent
+ - name: spire-agent-socket-dir
+ emptyDir: {}
+ # This volume is where the socket for kubelet->driver communication lives
+ - name: spiffe-csi-socket-dir
+ hostPath:
+ path: /var/lib/kubelet/plugins/csi.spiffe.io
+ type: DirectoryOrCreate
+ # This volume is where the SPIFFE CSI driver mounts volumes
+ - name: mountpoint-dir
+ hostPath:
+ path: /var/lib/kubelet/pods
+ type: Directory
+ # This volume is where the node-driver-registrar registers the plugin
+ # with kubelet
+ - name: kubelet-plugin-registration-dir
+ hostPath:
+ path: /var/lib/kubelet/plugins_registry
+ type: Directory
diff --git a/Istio-Samples/sleep/README.md b/Istio-Samples/sleep/README.md
new file mode 100644
index 00000000..045df5c5
--- /dev/null
+++ b/Istio-Samples/sleep/README.md
@@ -0,0 +1,37 @@
+# Simple sleep service
+
+This sample consists of a simple service that does nothing but sleep.
+It's a ubuntu container with curl installed that can be used as a request source for invoking other services
+to experiment with Istio networking.
+
+To use it:
+
+1. Install Istio by following the [istio install instructions](https://istio.io/docs/setup/).
+
+1. Start the sleep service:
+
+ If you have [automatic sidecar injection](https://istio.io/docs/setup/additional-setup/sidecar-injection/#automatic-sidecar-injection) enabled:
+
+ ```bash
+ kubectl apply -f sleep.yaml
+ ```
+
+ Otherwise manually inject the sidecars before applying:
+
+ ```bash
+ kubectl apply -f <(istioctl kube-inject -f sleep.yaml)
+ ```
+
+1. Start some other services, for example, the [Bookinfo sample](https://istio.io/docs/examples/bookinfo/).
+
+ Now you can `kubectl exec` into the sleep service to experiment with Istio networking.
+ For example, the following commands can be used to call the Bookinfo `ratings` service:
+
+ ```bash
+ export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
+ kubectl exec -it $SLEEP_POD -c sleep -- curl http://ratings.default.svc.cluster.local:9080/ratings/1
+ {"id":1,"ratings":{"Reviewer1":5,"Reviewer2":4}}
+ ```
+
+You can also use the sleep service to test accessing services outside of the mesh.
+See [configuring egress](https://istio.io/docs/tasks/traffic-management/egress/) for details.
diff --git a/Istio-Samples/sleep/notsleep.yaml b/Istio-Samples/sleep/notsleep.yaml
new file mode 100644
index 00000000..898d4ab4
--- /dev/null
+++ b/Istio-Samples/sleep/notsleep.yaml
@@ -0,0 +1,78 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Notsleep service - based on the sleep service but has its own identity and affinity rule
+##################################################################################################
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: notsleep
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: notsleep
+ labels:
+ app: notsleep
+ service: notsleep
+spec:
+ ports:
+ - port: 80
+ name: http
+ selector:
+ app: notsleep
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: notsleep
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: notsleep
+ template:
+ metadata:
+ labels:
+ app: notsleep
+ spec:
+ affinity:
+ podAntiAffinity:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ - weight: 100
+ podAffinityTerm:
+ labelSelector:
+ matchExpressions:
+ - key: app
+ operator: In
+ values:
+ - productpage
+ topologyKey: kubernetes.io/hostname
+ terminationGracePeriodSeconds: 0
+ serviceAccountName: notsleep
+ containers:
+ - name: notsleep
+ image: curlimages/curl
+ command: ["/bin/sleep", "3650d"]
+ imagePullPolicy: IfNotPresent
+ volumeMounts:
+ - mountPath: /etc/sleep/tls
+ name: secret-volume
+ volumes:
+ - name: secret-volume
+ secret:
+ secretName: notsleep-secret
+ optional: true
+---
diff --git a/Istio-Samples/sleep/sleep-vault.yaml b/Istio-Samples/sleep/sleep-vault.yaml
new file mode 100644
index 00000000..b31196cf
--- /dev/null
+++ b/Istio-Samples/sleep/sleep-vault.yaml
@@ -0,0 +1,57 @@
+# Copyright 2019 Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Sleep service
+##################################################################################################
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: sleep
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: sleep
+ labels:
+ app: sleep
+ service: sleep
+spec:
+ ports:
+ - port: 80
+ name: http
+ selector:
+ app: sleep
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: sleep
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: sleep
+ template:
+ metadata:
+ labels:
+ app: sleep
+ spec:
+ serviceAccountName: vault-citadel-sa
+ containers:
+ - name: sleep
+ image: curlimages/curl
+ command: ["/bin/sleep", "infinity"]
+ imagePullPolicy: IfNotPresent
+---
diff --git a/Istio-Samples/sleep/sleep.yaml b/Istio-Samples/sleep/sleep.yaml
new file mode 100644
index 00000000..570086b9
--- /dev/null
+++ b/Istio-Samples/sleep/sleep.yaml
@@ -0,0 +1,66 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##################################################################################################
+# Sleep service
+##################################################################################################
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: sleep
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: sleep
+ labels:
+ app: sleep
+ service: sleep
+spec:
+ ports:
+ - port: 80
+ name: http
+ selector:
+ app: sleep
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: sleep
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: sleep
+ template:
+ metadata:
+ labels:
+ app: sleep
+ spec:
+ terminationGracePeriodSeconds: 0
+ serviceAccountName: sleep
+ containers:
+ - name: sleep
+ image: curlimages/curl
+ command: ["/bin/sleep", "infinity"]
+ imagePullPolicy: IfNotPresent
+ volumeMounts:
+ - mountPath: /etc/sleep/tls
+ name: secret-volume
+ volumes:
+ - name: secret-volume
+ secret:
+ secretName: sleep-secret
+ optional: true
+---
diff --git a/Istio-Samples/tcp-echo/README.md b/Istio-Samples/tcp-echo/README.md
new file mode 100644
index 00000000..50f2d82a
--- /dev/null
+++ b/Istio-Samples/tcp-echo/README.md
@@ -0,0 +1,38 @@
+# TCP Echo Service
+
+This sample runs [TCP Echo Server](src/) as an Istio service. TCP Echo Server
+allows you to connect to it over TCP and echoes back data sent to it along with
+a preconfigured prefix.
+
+## Usage
+
+To run the TCP Echo Service sample:
+
+1. Install Istio by following the [istio install instructions](https://istio.io/docs/setup/kubernetes/quick-start.html).
+
+1. Start the `tcp-echo-server` service inside the Istio service mesh:
+
+ ```console
+ $ kubectl apply -f <(istioctl kube-inject -f tcp-echo.yaml)
+ service/tcp-echo created
+ deployment.apps/tcp-echo created
+ ```
+
+1. Test by running the `nc` command from a `busybox` container from within the cluster.
+
+ ```console
+ $ kubectl run -i --rm --restart=Never dummy --image=busybox -- sh -c "echo world | nc tcp-echo 9000"
+ hello world
+ pod "dummy" deleted
+ ```
+
+ As you observe, sending _world_ on a TCP connection to the server results in
+ the server prepending _hello_ and echoing back with _hello world_.
+
+1. To clean up, execute the following command:
+
+ ```console
+ $ kubectl delete -f tcp-echo.yaml
+ service "tcp-echo" deleted
+ deployment.apps "tcp-echo" deleted
+ ```
diff --git a/Istio-Samples/tcp-echo/gateway-api/tcp-echo-20-v2.yaml b/Istio-Samples/tcp-echo/gateway-api/tcp-echo-20-v2.yaml
new file mode 100644
index 00000000..11e27be3
--- /dev/null
+++ b/Istio-Samples/tcp-echo/gateway-api/tcp-echo-20-v2.yaml
@@ -0,0 +1,16 @@
+apiVersion: gateway.networking.k8s.io/v1alpha2
+kind: TCPRoute
+metadata:
+ name: tcp-echo
+spec:
+ parentRefs:
+ - name: tcp-echo-gateway
+ sectionName: tcp-31400
+ rules:
+ - backendRefs:
+ - name: tcp-echo-v1
+ port: 9000
+ weight: 80
+ - name: tcp-echo-v2
+ port: 9000
+ weight: 20
diff --git a/Istio-Samples/tcp-echo/gateway-api/tcp-echo-all-v1.yaml b/Istio-Samples/tcp-echo/gateway-api/tcp-echo-all-v1.yaml
new file mode 100644
index 00000000..23965bbc
--- /dev/null
+++ b/Istio-Samples/tcp-echo/gateway-api/tcp-echo-all-v1.yaml
@@ -0,0 +1,50 @@
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: Gateway
+metadata:
+ name: tcp-echo-gateway
+spec:
+ gatewayClassName: istio
+ listeners:
+ - name: tcp-31400
+ protocol: TCP
+ port: 31400
+ allowedRoutes:
+ kinds:
+ - kind: TCPRoute
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: tcp-echo-v1
+spec:
+ ports:
+ - port: 9000
+ name: tcp
+ selector:
+ app: tcp-echo
+ version: v1
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: tcp-echo-v2
+spec:
+ ports:
+ - port: 9000
+ name: tcp
+ selector:
+ app: tcp-echo
+ version: v2
+---
+apiVersion: gateway.networking.k8s.io/v1alpha2
+kind: TCPRoute
+metadata:
+ name: tcp-echo
+spec:
+ parentRefs:
+ - name: tcp-echo-gateway
+ sectionName: tcp-31400
+ rules:
+ - backendRefs:
+ - name: tcp-echo-v1
+ port: 9000
diff --git a/Istio-Samples/tcp-echo/src/Dockerfile b/Istio-Samples/tcp-echo/src/Dockerfile
new file mode 100644
index 00000000..f3601d6a
--- /dev/null
+++ b/Istio-Samples/tcp-echo/src/Dockerfile
@@ -0,0 +1,40 @@
+# Copyright 2018 Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# BASE_DISTRIBUTION is used to switch between the old base distribution and distroless base images
+ARG BASE_DISTRIBUTION=default
+
+# build a tcp-echo binary using the golang container
+FROM golang:1.19 as builder
+WORKDIR /go/src/istio.io/tcp-echo-server/
+COPY main.go .
+RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o tcp-echo main.go
+
+# The following section is used as base image if BASE_DISTRIBUTION=default
+# No tag available https://hub.docker.com/_/scratch?tab=description
+# hadolint ignore=DL3006
+FROM scratch as default
+
+# The following section is used as base image if BASE_DISTRIBUTION=distroless
+FROM gcr.io/distroless/static-debian10@sha256:4433370ec2b3b97b338674b4de5ffaef8ce5a38d1c9c0cb82403304b8718cde9 as distroless
+
+# This will build the final image based on either default or distroless from above
+# hadolint ignore=DL3006
+FROM ${BASE_DISTRIBUTION:-debug}
+WORKDIR /bin/
+# copy the tcp-echo binary to a separate container based on BASE_DISTRIBUTION
+COPY --from=builder /go/src/istio.io/tcp-echo-server/tcp-echo .
+ENTRYPOINT [ "/bin/tcp-echo" ]
+CMD [ "9000", "hello" ]
+EXPOSE 9000
diff --git a/Istio-Samples/tcp-echo/src/main.go b/Istio-Samples/tcp-echo/src/main.go
new file mode 100644
index 00000000..c132fbc9
--- /dev/null
+++ b/Istio-Samples/tcp-echo/src/main.go
@@ -0,0 +1,86 @@
+// Copyright Istio Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "strings"
+)
+
+// main serves as the program entry point
+func main() {
+ if len(os.Args) != 3 {
+ fmt.Println("you should run it like: 'main [PORTS...] prefix' , please notice PORTS are comma-delineated , like port 1[,port 2] ")
+ os.Exit(1)
+ }
+ // obtain the port and prefix via program arguments
+ ports := strings.Split(os.Args[1], ",")
+ prefix := os.Args[2]
+ for _, port := range ports {
+ addr := fmt.Sprintf(":%s", port)
+ go serve(addr, prefix)
+ }
+ ch := make(chan struct{})
+ <-ch
+}
+
+// serve starts serving on a given address
+func serve(addr, prefix string) {
+ // create a tcp listener on the given port
+ listener, err := net.Listen("tcp", addr)
+ if err != nil {
+ fmt.Println("failed to create listener, err:", err)
+ os.Exit(1)
+ }
+ fmt.Printf("listening on %s, prefix: %s\n", listener.Addr(), prefix)
+
+ // listen for new connections
+ for {
+ conn, err := listener.Accept()
+ if err != nil {
+ fmt.Println("failed to accept connection, err:", err)
+ continue
+ }
+
+ // pass an accepted connection to a handler goroutine
+ go handleConnection(conn, prefix)
+ }
+}
+
+// handleConnection handles the lifetime of a connection
+func handleConnection(conn net.Conn, prefix string) {
+ defer conn.Close()
+ reader := bufio.NewReader(conn)
+ for {
+ // read client request data
+ bytes, err := reader.ReadBytes(byte('\n'))
+ if err != nil {
+ if err != io.EOF {
+ fmt.Println("failed to read data, err:", err)
+ }
+ return
+ }
+ fmt.Printf("request: %s", bytes)
+
+ // prepend prefix and send as response
+ line := fmt.Sprintf("%s %s", prefix, bytes)
+ fmt.Printf("response: %s", line)
+ conn.Write([]byte(line))
+ }
+}
diff --git a/Istio-Samples/tcp-echo/src/main_test.go b/Istio-Samples/tcp-echo/src/main_test.go
new file mode 100644
index 00000000..9400e82f
--- /dev/null
+++ b/Istio-Samples/tcp-echo/src/main_test.go
@@ -0,0 +1,60 @@
+// Copyright Istio Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "bufio"
+ "net"
+ "os"
+ "strings"
+ "testing"
+ "time"
+)
+
+// TestTcpEchoServer tests the behavior of the TCP Echo Server.
+func TestTcpEchoServer(t *testing.T) {
+ // set up test parameters
+ prefix := "hello"
+ request := "world"
+ want := prefix + " " + request
+
+ // start the TCP Echo Server
+ os.Args = []string{"main", "9000,9001", prefix}
+ go main()
+
+ // wait for the TCP Echo Server to start
+ time.Sleep(500 * time.Millisecond)
+
+ for _, addr := range []string{":9000", ":9001"} {
+ // connect to the TCP Echo Server
+ conn, err := net.Dial("tcp", addr)
+ if err != nil {
+ t.Fatalf("couldn't connect to the server: %v", err)
+ }
+ defer conn.Close()
+
+ // test the TCP Echo Server output
+ if _, err := conn.Write([]byte(request + "\n")); err != nil {
+ t.Fatalf("couldn't send request: %v", err)
+ } else {
+ reader := bufio.NewReader(conn)
+ if response, err := reader.ReadBytes(byte('\n')); err != nil {
+ t.Fatalf("couldn't read server response: %v", err)
+ } else if !strings.HasPrefix(string(response), want) {
+ t.Errorf("output doesn't match, wanted: %s, got: %s", want, response)
+ }
+ }
+ }
+}
diff --git a/Istio-Samples/tcp-echo/tcp-echo-20-v2.yaml b/Istio-Samples/tcp-echo/tcp-echo-20-v2.yaml
new file mode 100644
index 00000000..f69ab115
--- /dev/null
+++ b/Istio-Samples/tcp-echo/tcp-echo-20-v2.yaml
@@ -0,0 +1,39 @@
+# Copyright 2018 Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: tcp-echo
+spec:
+ hosts:
+ - "*"
+ gateways:
+ - tcp-echo-gateway
+ tcp:
+ - match:
+ - port: 31400
+ route:
+ - destination:
+ host: tcp-echo
+ port:
+ number: 9000
+ subset: v1
+ weight: 80
+ - destination:
+ host: tcp-echo
+ port:
+ number: 9000
+ subset: v2
+ weight: 20
diff --git a/Istio-Samples/tcp-echo/tcp-echo-all-v1.yaml b/Istio-Samples/tcp-echo/tcp-echo-all-v1.yaml
new file mode 100644
index 00000000..3c302c51
--- /dev/null
+++ b/Istio-Samples/tcp-echo/tcp-echo-all-v1.yaml
@@ -0,0 +1,61 @@
+# Copyright 2018 Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: networking.istio.io/v1alpha3
+kind: Gateway
+metadata:
+ name: tcp-echo-gateway
+spec:
+ selector:
+ istio: ingressgateway
+ servers:
+ - port:
+ number: 31400
+ name: tcp
+ protocol: TCP
+ hosts:
+ - "*"
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+ name: tcp-echo-destination
+spec:
+ host: tcp-echo
+ subsets:
+ - name: v1
+ labels:
+ version: v1
+ - name: v2
+ labels:
+ version: v2
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: tcp-echo
+spec:
+ hosts:
+ - "*"
+ gateways:
+ - tcp-echo-gateway
+ tcp:
+ - match:
+ - port: 31400
+ route:
+ - destination:
+ host: tcp-echo
+ port:
+ number: 9000
+ subset: v1
diff --git a/Istio-Samples/tcp-echo/tcp-echo-dual-stack.yaml b/Istio-Samples/tcp-echo/tcp-echo-dual-stack.yaml
new file mode 100644
index 00000000..dd72061d
--- /dev/null
+++ b/Istio-Samples/tcp-echo/tcp-echo-dual-stack.yaml
@@ -0,0 +1,62 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# tcp-echo service
+################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: tcp-echo
+ labels:
+ app: tcp-echo
+ service: tcp-echo
+spec:
+ ipFamilyPolicy: RequireDualStack
+ ipFamilies:
+ - IPv6
+ - IPv4
+ ports:
+ - name: tcp
+ port: 9000
+ - name: tcp-other
+ port: 9001
+ # Port 9002 is omitted intentionally for testing the pass through filter chain.
+ selector:
+ app: tcp-echo
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: tcp-echo
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: tcp-echo
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: tcp-echo
+ version: v1
+ spec:
+ containers:
+ - name: tcp-echo
+ image: docker.io/istio/tcp-echo-server:1.2
+ imagePullPolicy: IfNotPresent
+ args: [ "9000,9001,9002", "hello" ]
+ ports:
+ - containerPort: 9000
+ - containerPort: 9001
diff --git a/Istio-Samples/tcp-echo/tcp-echo-ipv4.yaml b/Istio-Samples/tcp-echo/tcp-echo-ipv4.yaml
new file mode 100644
index 00000000..8ac98630
--- /dev/null
+++ b/Istio-Samples/tcp-echo/tcp-echo-ipv4.yaml
@@ -0,0 +1,61 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# tcp-echo service
+################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: tcp-echo
+ labels:
+ app: tcp-echo
+ service: tcp-echo
+spec:
+ ipFamilyPolicy: SingleStack
+ ipFamilies:
+ - IPv4
+ ports:
+ - name: tcp
+ port: 9000
+ - name: tcp-other
+ port: 9001
+ # Port 9002 is omitted intentionally for testing the pass through filter chain.
+ selector:
+ app: tcp-echo
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: tcp-echo
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: tcp-echo
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: tcp-echo
+ version: v1
+ spec:
+ containers:
+ - name: tcp-echo
+ image: docker.io/istio/tcp-echo-server:1.2
+ imagePullPolicy: Always
+ args: [ "9000,9001,9002", "hello" ]
+ ports:
+ - containerPort: 9000
+ - containerPort: 9001
diff --git a/Istio-Samples/tcp-echo/tcp-echo-ipv6.yaml b/Istio-Samples/tcp-echo/tcp-echo-ipv6.yaml
new file mode 100644
index 00000000..02ddd6de
--- /dev/null
+++ b/Istio-Samples/tcp-echo/tcp-echo-ipv6.yaml
@@ -0,0 +1,61 @@
+# Copyright Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# tcp-echo service
+################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: tcp-echo
+ labels:
+ app: tcp-echo
+ service: tcp-echo
+spec:
+ ipFamilyPolicy: SingleStack
+ ipFamilies:
+ - IPv6
+ ports:
+ - name: tcp
+ port: 9000
+ - name: tcp-other
+ port: 9001
+ # Port 9002 is omitted intentionally for testing the pass through filter chain.
+ selector:
+ app: tcp-echo
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: tcp-echo
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: tcp-echo
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: tcp-echo
+ version: v1
+ spec:
+ containers:
+ - name: tcp-echo
+ image: docker.io/istio/tcp-echo-server:1.2
+ imagePullPolicy: IfNotPresent
+ args: [ "9000,9001,9002", "hello" ]
+ ports:
+ - containerPort: 9000
+ - containerPort: 9001
diff --git a/Istio-Samples/tcp-echo/tcp-echo-services.yaml b/Istio-Samples/tcp-echo/tcp-echo-services.yaml
new file mode 100644
index 00000000..7f645746
--- /dev/null
+++ b/Istio-Samples/tcp-echo/tcp-echo-services.yaml
@@ -0,0 +1,86 @@
+# Copyright 2018 Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: tcp-echo
+ labels:
+ app: tcp-echo
+ service: tcp-echo
+spec:
+ ports:
+ - name: tcp
+ port: 9000
+ - name: tcp-other
+ port: 9001
+ # Port 9002 is omitted intentionally for testing the pass through filter chain.
+ selector:
+ app: tcp-echo
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: tcp-echo-v1
+ labels:
+ app: tcp-echo
+ version: v1
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: tcp-echo
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: tcp-echo
+ version: v1
+ spec:
+ containers:
+ - name: tcp-echo
+ image: docker.io/istio/tcp-echo-server:1.2
+ imagePullPolicy: IfNotPresent
+ args: [ "9000,9001,9002", "one" ]
+ ports:
+ - containerPort: 9000
+ - containerPort: 9001
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: tcp-echo-v2
+ labels:
+ app: tcp-echo
+ version: v2
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: tcp-echo
+ version: v2
+ template:
+ metadata:
+ labels:
+ app: tcp-echo
+ version: v2
+ spec:
+ containers:
+ - name: tcp-echo
+ image: docker.io/istio/tcp-echo-server:1.2
+ imagePullPolicy: IfNotPresent
+ args: [ "9000,9001,9002", "two" ]
+ ports:
+ - containerPort: 9000
+ - containerPort: 9001
diff --git a/Istio-Samples/tcp-echo/tcp-echo.yaml b/Istio-Samples/tcp-echo/tcp-echo.yaml
new file mode 100644
index 00000000..fae95161
--- /dev/null
+++ b/Istio-Samples/tcp-echo/tcp-echo.yaml
@@ -0,0 +1,58 @@
+# Copyright 2018 Istio Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# tcp-echo service
+################################################################################
+apiVersion: v1
+kind: Service
+metadata:
+ name: tcp-echo
+ labels:
+ app: tcp-echo
+ service: tcp-echo
+spec:
+ ports:
+ - name: tcp
+ port: 9000
+ - name: tcp-other
+ port: 9001
+ # Port 9002 is omitted intentionally for testing the pass through filter chain.
+ selector:
+ app: tcp-echo
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: tcp-echo
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: tcp-echo
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: tcp-echo
+ version: v1
+ spec:
+ containers:
+ - name: tcp-echo
+ image: docker.io/istio/tcp-echo-server:1.2
+ imagePullPolicy: IfNotPresent
+ args: [ "9000,9001,9002", "hello" ]
+ ports:
+ - containerPort: 9000
+ - containerPort: 9001
diff --git a/Istio-Samples/wasm_modules/README.md b/Istio-Samples/wasm_modules/README.md
new file mode 100644
index 00000000..4a8a8702
--- /dev/null
+++ b/Istio-Samples/wasm_modules/README.md
@@ -0,0 +1,3 @@
+# WASM demo
+
+`header_injector` is used for istio e2e tests, more tests can be found [here](https://github.com/istio-ecosystem/wasm-extensions).
diff --git a/Istio-Samples/wasm_modules/header_injector/.gitignore b/Istio-Samples/wasm_modules/header_injector/.gitignore
new file mode 100644
index 00000000..b3987b57
--- /dev/null
+++ b/Istio-Samples/wasm_modules/header_injector/.gitignore
@@ -0,0 +1,3 @@
+bazel-*
+compile_commands.json
+*.wasm
\ No newline at end of file
diff --git a/Istio-Samples/wasm_modules/header_injector/BUILD b/Istio-Samples/wasm_modules/header_injector/BUILD
new file mode 100644
index 00000000..327c2306
--- /dev/null
+++ b/Istio-Samples/wasm_modules/header_injector/BUILD
@@ -0,0 +1,29 @@
+load("@proxy_wasm_cpp_sdk//bazel/wasm:wasm.bzl", "wasm_cc_binary")
+
+wasm_cc_binary(
+ name = "plugin-0.0.1.wasm",
+ srcs = [
+ "plugin.cc",
+ "plugin.h",
+ ],
+ deps = [
+ "@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
+ ],
+ defines = [
+ "INJECTION_VERSION=0.0.1"
+ ],
+)
+
+wasm_cc_binary(
+ name = "plugin-0.0.2.wasm",
+ srcs = [
+ "plugin.cc",
+ "plugin.h",
+ ],
+ deps = [
+ "@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
+ ],
+ defines = [
+ "INJECTION_VERSION=0.0.2"
+ ],
+)
\ No newline at end of file
diff --git a/Istio-Samples/wasm_modules/header_injector/Dockerfile b/Istio-Samples/wasm_modules/header_injector/Dockerfile
new file mode 100644
index 00000000..f09a9468
--- /dev/null
+++ b/Istio-Samples/wasm_modules/header_injector/Dockerfile
@@ -0,0 +1,4 @@
+FROM scratch
+ARG WASM_BINARY
+WORKDIR /
+COPY $WASM_BINARY /plugin.wasm
diff --git a/Istio-Samples/wasm_modules/header_injector/Makefile b/Istio-Samples/wasm_modules/header_injector/Makefile
new file mode 100644
index 00000000..377495d2
--- /dev/null
+++ b/Istio-Samples/wasm_modules/header_injector/Makefile
@@ -0,0 +1,22 @@
+.PHONY: docker-push docker-build build clean
+
+VERSION_LIST := 1 2
+HUB ?= gcr.io/istio-testing
+IMAGE_PREFIX ?= /wasm
+IMG := $(HUB)$(IMAGE_PREFIX)/header-injector
+
+all: docker-push
+
+build: plugin.cc plugin.h BUILD WORKSPACE
+ rm -f *.wasm
+ $(foreach VERSION, $(VERSION_LIST), bazel build :plugin-0.0.$(VERSION).wasm && cp bazel-bin/plugin-0.0.$(VERSION).wasm .;)
+
+docker-build: build
+ $(foreach VERSION, $(VERSION_LIST), docker buildx build . -t $(IMG):0.0.$(VERSION) --build-arg WASM_BINARY=plugin-0.0.$(VERSION).wasm;)
+
+docker-push: docker-build
+ $(foreach VERSION, $(VERSION_LIST), docker push $(IMG):0.0.$(VERSION);)
+
+clean:
+ rm -rf bazel-*
+ rm -f *.wasm
diff --git a/Istio-Samples/wasm_modules/header_injector/WORKSPACE b/Istio-Samples/wasm_modules/header_injector/WORKSPACE
new file mode 100644
index 00000000..33cda8d1
--- /dev/null
+++ b/Istio-Samples/wasm_modules/header_injector/WORKSPACE
@@ -0,0 +1,22 @@
+workspace(name = "header_injector_extension")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+# Pulls proxy wasm cpp SDK with a specific SHA
+PROXY_WASM_CPP_SDK_SHA = "fd0be8405db25de0264bdb78fae3a82668c03782"
+PROXY_WASM_CPP_SDK_SHA256 = "c57de2425b5c61d7f630c5061e319b4557ae1f1c7526e5a51c33dc1299471b08"
+
+http_archive(
+ name = "proxy_wasm_cpp_sdk",
+ sha256 = PROXY_WASM_CPP_SDK_SHA256,
+ strip_prefix = "proxy-wasm-cpp-sdk-" + PROXY_WASM_CPP_SDK_SHA,
+ url = "https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/" + PROXY_WASM_CPP_SDK_SHA + ".tar.gz",
+)
+
+load("@proxy_wasm_cpp_sdk//bazel/dep:deps.bzl", "wasm_dependencies")
+
+wasm_dependencies()
+
+load("@proxy_wasm_cpp_sdk//bazel/dep:deps_extra.bzl", "wasm_dependencies_extra")
+
+wasm_dependencies_extra()
\ No newline at end of file
diff --git a/Istio-Samples/wasm_modules/header_injector/plugin.cc b/Istio-Samples/wasm_modules/header_injector/plugin.cc
new file mode 100644
index 00000000..cd3bcaa5
--- /dev/null
+++ b/Istio-Samples/wasm_modules/header_injector/plugin.cc
@@ -0,0 +1,38 @@
+// Copyright Istio Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "plugin.h"
+
+#ifndef INJECTION_VERSION
+#error INJECTION_VERSION must be defined
+#endif // INJECTION_VERSION
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+// Boilderplate code to register the extension implementation.
+static RegisterContextFactory register_HeaderInjector(CONTEXT_FACTORY(HeaderInjectorContext),
+ ROOT_FACTORY(HeaderInjectorRootContext));
+
+bool HeaderInjectorRootContext::onConfigure(size_t) { return true; }
+
+FilterHeadersStatus HeaderInjectorContext::onRequestHeaders(uint32_t, bool) {
+ addRequestHeader("X-Req-Injection", xstr(INJECTION_VERSION));
+ return FilterHeadersStatus::Continue;
+}
+
+FilterHeadersStatus HeaderInjectorContext::onResponseHeaders(uint32_t, bool) {
+ addResponseHeader("X-Resp-Injection", xstr(INJECTION_VERSION));
+ return FilterHeadersStatus::Continue;
+}
\ No newline at end of file
diff --git a/Istio-Samples/wasm_modules/header_injector/plugin.h b/Istio-Samples/wasm_modules/header_injector/plugin.h
new file mode 100644
index 00000000..6d21919d
--- /dev/null
+++ b/Istio-Samples/wasm_modules/header_injector/plugin.h
@@ -0,0 +1,36 @@
+// Copyright Istio Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "proxy_wasm_intrinsics.h"
+
+class HeaderInjectorRootContext : public RootContext {
+ public:
+ explicit HeaderInjectorRootContext(uint32_t id, std::string_view root_id)
+ : RootContext(id, root_id) {}
+
+ bool onConfigure(size_t) override;
+};
+
+class HeaderInjectorContext : public Context {
+ public:
+ explicit HeaderInjectorContext(uint32_t id, RootContext* root) : Context(id, root) {}
+
+ FilterHeadersStatus onRequestHeaders(uint32_t, bool) override;
+ FilterHeadersStatus onResponseHeaders(uint32_t, bool) override;
+
+ private:
+ inline HeaderInjectorRootContext* rootContext() {
+ return dynamic_cast(this->root());
+ }
+};
\ No newline at end of file
diff --git a/Istio-Samples/websockets/README.md b/Istio-Samples/websockets/README.md
new file mode 100644
index 00000000..26a1f382
--- /dev/null
+++ b/Istio-Samples/websockets/README.md
@@ -0,0 +1,48 @@
+# Tornado - Demo Websockets App
+
+This is a sample application that demonstrates the use of an upgraded websockets connection on an ingress traffic when using Istio `VirtualService`.
+The `app.yaml` creates a Kubernetes `Service` and a `Deployment` that is based on an existing Docker image for [Hiroakis's Tornado Websocket Example](https://github.com/hiroakis/tornado-websocket-example).
+
+__Notice:__ The addition of websockets upgrade support in v1alpha3 routing rules has only been added after the release of `Istio v0.8.0`.
+
+## Prerequisites
+
+Install Istio by following the [Istio Quick Start](https://istio.io/docs/setup/kubernetes/quick-start.html).
+
+## Installation
+
+1. First install the application service:
+
+ - With manual sidecar injection:
+
+ ```command
+ kubectl create -f <(istioctl kube-inject -f samples/websockets/app.yaml)
+ ```
+
+ - With automatic sidecar injection
+
+ ```command
+ kubectl create -f samples/websockets/app.yaml
+ ```
+
+1. Create the Ingress `Gateway` and `VirtualService` that enables the upgrade to Websocket for incoming traffic:
+
+ ```command
+ kubectl create -f samples/websockets/route.yaml
+ ```
+
+## Test
+
+- [Find your ingress gateway IP](https://istio.io/docs/tasks/traffic-management/ingress/#determining-the-ingress-ip-and-ports)
+
+- Access with your browser
+
+- The `WebSocket status` should show a green `open` status which means that a websocket connection to the server has been established.
+To see the websocket in action see the instructions in the _REST API examples_ section of the demo app webpage for updating the server-side data and getting the updated data through the open websocket to the table in the webpage (without refreshing).
+
+## Cleanup
+
+```command
+kubectl delete -f samples/websockets/route.yaml
+kubectl delete -f samples/websockets/app.yaml
+```
diff --git a/Istio-Samples/websockets/app.yaml b/Istio-Samples/websockets/app.yaml
new file mode 100644
index 00000000..4f44ea7d
--- /dev/null
+++ b/Istio-Samples/websockets/app.yaml
@@ -0,0 +1,37 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: tornado
+ labels:
+ app: tornado
+ service: tornado
+spec:
+ ports:
+ - port: 8888
+ name: http
+ selector:
+ app: tornado
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: tornado
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: tornado
+ version: v1
+ template:
+ metadata:
+ labels:
+ app: tornado
+ version: v1
+ spec:
+ containers:
+ - name: tornado
+ image: hiroakis/tornado-websocket-example
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 8888
+---
diff --git a/Istio-Samples/websockets/route.yaml b/Istio-Samples/websockets/route.yaml
new file mode 100644
index 00000000..ef580b2c
--- /dev/null
+++ b/Istio-Samples/websockets/route.yaml
@@ -0,0 +1,32 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: Gateway
+metadata:
+ name: tornado-gateway
+spec:
+ selector:
+ istio: ingressgateway
+ servers:
+ - port:
+ number: 80
+ name: http
+ protocol: HTTP
+ hosts:
+ - "*"
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+ name: tornado
+spec:
+ hosts:
+ - "*"
+ gateways:
+ - tornado-gateway
+ http:
+ - match:
+ - uri:
+ prefix: /
+ route:
+ - destination:
+ host: tornado
+ weight: 100
diff --git a/Kubernetes pocket guide.pdf b/Kubernetes pocket guide.pdf
new file mode 100644
index 00000000..cc924836
Binary files /dev/null and b/Kubernetes pocket guide.pdf differ
diff --git a/Kubernetes-Basic-2-Days/Modules/LoadBalancer-service.yaml b/Kubernetes-Basic-2-Days/Modules/LoadBalancer-service.yaml
new file mode 100644
index 00000000..15d3c150
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/LoadBalancer-service.yaml
@@ -0,0 +1,17 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: my-service
+spec:
+ selector:
+ app.kubernetes.io/name: MyApp
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 9376
+ clusterIP: 10.0.171.239
+ type: LoadBalancer
+status:
+ loadBalancer:
+ ingress:
+ - ip: 192.0.2.127
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/README.md b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/README.md
new file mode 100644
index 00000000..e19f7c93
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/README.md
@@ -0,0 +1,206 @@
+Table of Contents
+=================
+
+- [Table of Contents](#table-of-contents)
+- [Ingress](#ingress)
+ - [What is Ingress?](#what-is-ingress)
+ - [Prerequisites](#prerequisites)
+ - [The Ingress resource](#the-ingress-resource)
+ - [Ingress rules](#ingress-rules)
+ - [Path types](#path-types)
+ - [Examples](#examples)
+ - [Multiple matches](#multiple-matches)
+ - [Hostname wildcards](#hostname-wildcards)
+ - [Ingress class](#ingress-class)
+ - [Types of Ingress](#types-of-ingress)
+ - [Ingress backed by a single Service](#ingress-backed-by-a-single-service)
+ - [Simple fanout](#simple-fanout)
+ - [Name based virtual hosting](#name-based-virtual-hosting)
+
+# Ingress
+
+It manages external access to the services in a cluster, typically HTTP.
+
+Ingress may provide load balancing, SSL termination and name-based virtual hosting.
+
+## What is Ingress?
+
+Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster. Traffic routing is controlled by rules defined on the Ingress resource.
+
+Here is a simple example where an Ingress sends all its traffic to one Service:
+
+![ingress-diagram](/images/ingress.png)
+
+Figure. Ingress
+
+An Ingress may be configured to give Services externally-reachable URLs, load balance traffic, terminate SSL / TLS, and offer name-based virtual hosting.
+
+An _Ingress controller_ is responsible for fulfilling the Ingress, usually with a load balancer, though it may also configure your edge router or additional frontends to help handle the traffic.
+
+An Ingress does not expose arbitrary ports or protocols. Exposing services other than HTTP and HTTPS to the internet typically uses a service of type _Service.Type=NodePort_ or _Service.Type=LoadBalancer_.
+
+## Prerequisites
+
+You must have an Ingress controller to satisfy an Ingress. Only creating an Ingress resource has no effect.
+
+Ideally, all Ingress controllers should fit the reference specification. In reality, the various Ingress controllers operate slightly differently.
+
+
+## The Ingress resource
+
+Please refer to `minimal-ingress.yaml`
+
+### Ingress rules
+
+Each HTTP rule contains the following information:
+
+- An optional host. In this example, no host is specified, so the rule applies to all inbound HTTP traffic through the IP address specified. If a host is provided (for example, foo.bar.com), the rules apply to that host.
+
+- A list of paths (for example, `/testpath`), each of which has an associated backend defined with a `service.name` and a `service.port.name` or `service.port.number`. Both the host and path must match the content of an incoming request before the load balancer directs traffic to the referenced Service.
+
+- A backend is a combination of Service and port names as described in the Service doc or a custom resource backend by way of a CRD. HTTP (and HTTPS) requests to the Ingress that matches the host and path of the rule are sent to the listed backend.
+
+
+### Path types
+
+Each path in an Ingress is required to have a corresponding path type. Paths that do not include an explicit `pathType` will fail validation. There are three supported path types:
+
+- `ImplementationSpecific`: With this path type, matching is up to the IngressClass. Implementations can treat this as a separate `pathType` or treat it identically to `Prefix` or `Exact` path types.
+
+- `Exact`: Matches the URL path exactly and with case sensitivity.
+
+- `Prefix`: Matches based on a URL path prefix split by `/`. Matching is case sensitive and done on a path element by element basis. A path element refers to the list of labels in the path split by the `/` separator. A request is a match for path _p_ if every _p_ is an element-wise prefix of _p_ of the request path.
+
+> **Note:** If the last element of the path is a substring of the last element in request path, it is not a match (for example: `/foo/bar` matches`/foo/bar/baz`, but does not match `/foo/barbaz`).
+
+
+## Examples
+
+| Kind | Path(s) | Request path(s) | Matches? |
+| --- | --- | --- | --- |
+| Prefix | / | (all paths) | Yes |
+|Exact| /foo |/foo| Yes|
+|Exact| /foo |/bar| No|
+|Exact| /foo| /foo/| No|
+|Exact| /foo/ |/foo| No|
+|Prefix| /foo| /foo, /foo/ |Yes
+|Prefix| /foo/| /foo, /foo/ |Yes
+|Prefix| /aaa/bb| /aaa/bbb |No
+|Prefix| /aaa/bbb| /aaa/bbb |Yes
+|Prefix| /aaa/bbb/| /aaa/bbb |Yes, ignores trailing slash
+|Prefix| /aaa/bbb| /aaa/bbb/ |Yes, matches trailing slash
+|Prefix| /aaa/bbb| /aaa/bbb/ccc |Yes, matches subpath
+|Prefix| /aaa/bbb| /aaa/bbbxyz |No, does not match string Prefix
+|Prefix| /, /aaa| /aaa/ccc |Yes, matches /aaa Prefix
+|Prefix| /, /aaa, /aaa/bbb |/aaa/bbb |Yes, matches /aaa/bbb Prefix
+|Prefix| /, /aaa, /aaa/bbb| /ccc |Yes, matches / Prefix
+|Prefix| /aaa| /ccc |No, uses default backend
+|Mixed| /foo (Prefix), /foo (Exact)| /foo |Yes, prefers Exact
+
+
+#### Multiple matches
+
+In some cases, multiple paths within an Ingress will match a request. In those cases precedence will be given first to the longest matching path. If two paths are still equally matched, precedence will be given to paths with an exact path type over prefix path type.
+
+
+## Hostname wildcards
+
+Hosts can be precise matches (for example “`foo.bar.com`”) or a wildcard (for example “`*.foo.com`”). Precise matches require that the HTTP `host` header matches the `host` field. Wildcard matches require the HTTP `host` header is equal to the suffix of the wildcard rule.
+
+| Host | Host header | Match? |
+| --- | --- | --- |
+|`*.foo.com`|`bar.foo.com`|Matches based on shared suffix|
+|`*.foo.com`|`baz.bar.foo.com`|No match, wildcard only covers a single DNS label|
+|`*.foo.com`|`foo.com`|No match, wildcard only covers a single DNS label|
+
+see `ingress-wildcard-host.yaml`
+
+## Ingress class
+
+Ingresses can be implemented by different controllers, often with different configuration.
+
+Each Ingress should specify a class, a reference to an IngressClass resource that contains additional configuration including the name of the controller that should implement the class.
+
+see `default-ingressclass.yaml`
+
+## Types of Ingress
+
+### Ingress backed by a single Service
+
+There are existing Kubernetes concepts that allow you to expose a single Service. You can also do this with an Ingress by specifying a _default backend_ with no rules.
+
+see `test-ingress.yaml`
+
+If you create it using `kubectl apply -f test-ingress.yaml` you should be able to view the state of the Ingress you added:
+
+```bash
+kubectl get ingress test-ingress
+```
+
+```
+NAME CLASS HOSTS ADDRESS PORTS AGE
+test-ingress external-lb * 203.0.113.123 80 59s
+```
+
+Where `203.0.113.123` is the IP allocated by the Ingress controller to satisfy this Ingress.
+
+### Simple fanout
+
+A fanout configuration routes traffic from a single IP address to more than one Service, based on the HTTP URI being requested.
+
+An Ingress allows you to keep the number of load balancers down to a minimum. For example, a setup like:
+
+![ingress-fanout-diagram](/images/IngressFanOut.png)
+
+Figure. Ingress Fan Out
+
+would require an Ingress such as:
+
+see `simple-fanout-example.yaml`
+
+When you create the Ingress with `kubectl apply -f simple-fanout-example.yaml` :
+
+```shell
+kubectl describe ingress simple-fanout-example
+```
+
+```
+Name: simple-fanout-example
+Namespace: default
+Address: 178.91.123.132
+Default backend: default-http-backend:80 (10.8.2.3:8080)
+Rules:
+ Host Path Backends
+ ---- ---- --------
+ foo.bar.com
+ /foo service1:4200 (10.8.0.90:4200)
+ /bar service2:8080 (10.8.0.91:8080)
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal ADD 22s loadbalancer-controller default/test
+```
+
+The Ingress controller provisions an implementation-specific load balancer that satisfies the Ingress, as long as the Services (`service1`, `service2`) exist.
+
+When it has done so, you can see the address of the load balancer at the Address field.
+
+### Name based virtual hosting
+
+Name-based virtual hosts support routing HTTP traffic to multiple host names at the same IP address.
+
+![ingress-namebase-diagram](/images/ingressnamebased.png)
+
+Figure. Ingress Name Based Virtual hosting
+
+The following Ingress tells the backing load balancer to route requests based on the Host header.
+
+see `name-virtual-host-ingress.yaml`
+
+If you create an Ingress resource without any hosts defined in the rules, then any web traffic to the IP address of your Ingress controller can be matched without a name based virtual host being required.
+
+For example, the following Ingress routes traffic requested for `first.bar.com` to `service1`, `second.bar.com` to `service2`, and any traffic whose request host header doesn't match `first.bar.com` and `second.bar.com` to `service3`.
+
+see `name-virtual-host-ingress-no-third-host.yaml`
+
+Reference link: [Ingress Concepts](https://kubernetes.io/docs/concepts/services-networking/ingress/)
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/default-ingressclass.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/default-ingressclass.yaml
new file mode 100644
index 00000000..4b96eedd
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/default-ingressclass.yaml
@@ -0,0 +1,10 @@
+apiVersion: networking.k8s.io/v1
+kind: IngressClass
+metadata:
+ labels:
+ app.kubernetes.io/component: controller
+ name: nginx-example
+ annotations:
+ ingressclass.kubernetes.io/is-default-class: "true"
+spec:
+ controller: k8s.io/ingress-nginx
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/ingress-wildcard-host.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/ingress-wildcard-host.yaml
new file mode 100644
index 00000000..b1ffe772
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/ingress-wildcard-host.yaml
@@ -0,0 +1,26 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: ingress-wildcard-host
+spec:
+ rules:
+ - host: "foo.bar.com"
+ http:
+ paths:
+ - pathType: Prefix
+ path: "/bar"
+ backend:
+ service:
+ name: service1
+ port:
+ number: 80
+ - host: "*.foo.com"
+ http:
+ paths:
+ - pathType: Prefix
+ path: "/foo"
+ backend:
+ service:
+ name: service2
+ port:
+ number: 80
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/minimal-ingress.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/minimal-ingress.yaml
new file mode 100644
index 00000000..755e2d40
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/minimal-ingress.yaml
@@ -0,0 +1,18 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: minimal-ingress
+ annotations:
+ nginx.ingress.kubernetes.io/rewrite-target: /
+spec:
+ ingressClassName: nginx-example
+ rules:
+ - http:
+ paths:
+ - path: /testpath
+ pathType: Prefix
+ backend:
+ service:
+ name: test
+ port:
+ number: 80
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/name-virtual-host-ingress-no-third-host.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/name-virtual-host-ingress-no-third-host.yaml
new file mode 100644
index 00000000..9e9dae0f
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/name-virtual-host-ingress-no-third-host.yaml
@@ -0,0 +1,35 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: name-virtual-host-ingress-no-third-host
+spec:
+ rules:
+ - host: first.bar.com
+ http:
+ paths:
+ - pathType: Prefix
+ path: "/"
+ backend:
+ service:
+ name: service1
+ port:
+ number: 80
+ - host: second.bar.com
+ http:
+ paths:
+ - pathType: Prefix
+ path: "/"
+ backend:
+ service:
+ name: service2
+ port:
+ number: 80
+ - http:
+ paths:
+ - pathType: Prefix
+ path: "/"
+ backend:
+ service:
+ name: service3
+ port:
+ number: 80
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/name-virtual-host-ingress.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/name-virtual-host-ingress.yaml
new file mode 100644
index 00000000..37ff29cc
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/name-virtual-host-ingress.yaml
@@ -0,0 +1,26 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: name-virtual-host-ingress
+spec:
+ rules:
+ - host: foo.bar.com
+ http:
+ paths:
+ - pathType: Prefix
+ path: "/"
+ backend:
+ service:
+ name: service1
+ port:
+ number: 80
+ - host: bar.foo.com
+ http:
+ paths:
+ - pathType: Prefix
+ path: "/"
+ backend:
+ service:
+ name: service2
+ port:
+ number: 80
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/simple-fanout-example.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/simple-fanout-example.yaml
new file mode 100644
index 00000000..19adbcf6
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/simple-fanout-example.yaml
@@ -0,0 +1,23 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: simple-fanout-example
+spec:
+ rules:
+ - host: foo.bar.com
+ http:
+ paths:
+ - path: /foo
+ pathType: Prefix
+ backend:
+ service:
+ name: service1
+ port:
+ number: 4200
+ - path: /bar
+ pathType: Prefix
+ backend:
+ service:
+ name: service2
+ port:
+ number: 8080
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/test-ingress.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/test-ingress.yaml
new file mode 100644
index 00000000..3c91c499
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Ingress/test-ingress.yaml
@@ -0,0 +1,10 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: test-ingress
+spec:
+ defaultBackend:
+ service:
+ name: test
+ port:
+ number: 80
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/README.md b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/README.md
new file mode 100644
index 00000000..ffe24647
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/README.md
@@ -0,0 +1,244 @@
+Table of Contents
+=================
+
+- [Table of Contents](#table-of-contents)
+- [Network Policies](#network-policies)
+ - [The Two Sorts of Pod Isolation](#the-two-sorts-of-pod-isolation)
+ - [Egress](#egress)
+ - [Ingress](#ingress)
+ - [The NetworkPolicy resource](#the-networkpolicy-resource)
+ - [Behavior of `to` and `from` selectors](#behavior-oftoandfromselectors)
+ - [Default policies](#default-policies)
+ - [Default deny all ingress traffic](#default-deny-all-ingress-traffic)
+ - [Allow all ingress traffic](#allow-all-ingress-traffic)
+ - [Default deny all egress traffic](#default-deny-all-egress-traffic)
+ - [Allow all egress traffic](#allow-all-egress-traffic)
+ - [Default deny all ingress and all egress traffic](#default-deny-all-ingress-and-all-egress-traffic)
+
+# Network Policies
+
+If you want to control traffic flow at the IP address or port level (OSI layer 3 or 4), then you might consider using Kubernetes NetworkPolicies for particular applications in your cluster.
+
+NetworkPolicies are an application-centric construct which allow you to specify how a pod is allowed to communicate with various network "entities" (we use the word "entity" here to avoid overloading the more common terms such as "endpoints" and "services", which have specific Kubernetes connotations) over the network.
+
+NetworkPolicies apply to a connection with a pod on one or both ends, and are not relevant to other connections.
+
+The entities that a Pod can communicate with are identified through a combination of the following 3 identifiers:
+
+1. Other pods that are allowed (exception: a pod cannot block access to itself)
+2. Namespaces that are allowed
+3. IP blocks (exception: traffic to and from the node where a Pod is running is always allowed, regardless of the IP address of the Pod or the node)
+
+When defining a pod- or namespace- based NetworkPolicy, you use a selector to specify what traffic is allowed to and from the Pod(s) that match the selector.
+
+Meanwhile, when IP based NetworkPolicies are created, we define policies based on IP blocks (CIDR ranges).
+
+## The Two Sorts of Pod Isolation
+
+There are two sorts of isolation for a pod: isolation for egress, and isolation for ingress.
+
+They concern what connections may be established. "Isolation" here is not absolute, rather it means "some restrictions apply".
+
+The alternative, "non-isolated for direction", means that no restrictions apply in the stated direction. The two sorts of isolation (or not) are declared independently, and are both relevant for a connection from one pod to another.
+
+### Egress
+By default, a pod is non-isolated for egress; all outbound connections are allowed.
+
+A pod is isolated for egress if there is any NetworkPolicy that both selects the pod and has "Egress" in its `policyTypes`; we say that such a policy applies to the pod for egress.
+
+When a pod is isolated for egress, the only allowed connections from the pod are those allowed by the `egress` list of some NetworkPolicy that applies to the pod for egress. The effects of those `egress` lists combine additively.
+
+### Ingress
+
+By default, a pod is non-isolated for ingress; all inbound connections are allowed.
+
+A pod is isolated for ingress if there is any NetworkPolicy that both selects the pod and has "Ingress" in its `policyTypes`; we say that such a policy applies to the pod for ingress.
+
+When a pod is isolated for ingress, the only allowed connections into the pod are those from the pod's node and those allowed by the `ingress` list of some NetworkPolicy that applies to the pod for ingress. The effects of those `ingress` lists combine additively.
+
+Network policies do not `conflict`; they are `additive`.
+
+If any policy or policies apply to a given pod for a given direction, the connections allowed in that direction from that pod is the union of what the applicable policies allow. Thus, order of evaluation does not affect the policy result.
+
+For a connection from a source pod to a destination pod to be allowed, both the egress policy on the source pod and the ingress policy on the destination pod need to allow the connection. If either side does not allow the connection, it will not happen.
+
+## The NetworkPolicy resource
+
+Please refer to the `networkpolicy.yaml` and read below:
+
+1. isolates "role=db" pods in the "default" namespace for both ingress and egress traffic (if they weren't already isolated)
+
+2. (Ingress rules) allows connections to all pods in the "default" namespace with the label "role=db" on TCP port 6379 from:
+
+ - any pod in the "default" namespace with the label "role=frontend"
+ - any pod in a namespace with the label "project=myproject"
+ - IP addresses in the ranges 172.17.0.0–172.17.0.255 and 172.17.2.0–172.17.255.255 (ie, all of 172.17.0.0/16 except 172.17.1.0/24)
+3. (Egress rules) allows connections from any pod in the "default" namespace with the label "role=db" to CIDR 10.0.0.0/24 on TCP port 5978
+
+
+## Behavior of `to` and `from` selectors
+
+There are four kinds of selectors that can be specified in an `ingress` `from` section or `egress` `to` section:
+
+**podSelector**: This selects particular Pods in the same namespace as the NetworkPolicy which should be allowed as ingress sources or egress destinations.
+
+**namespaceSelector**: This selects particular namespaces for which all Pods should be allowed as ingress sources or egress destinations.
+
+**namespaceSelector** _and_ **podSelector**: A single `to`/`from` entry that specifies both `namespaceSelector` and `podSelector` selects particular Pods within particular namespaces. Be careful to use correct YAML syntax; this policy:
+
+```yaml
+ ...
+ ingress:
+ - from:
+ - namespaceSelector:
+ matchLabels:
+ user: alice
+ podSelector:
+ matchLabels:
+ role: client
+ ...
+```
+
+contains a single `from` element allowing connections from Pods with the label `role=client` in namespaces with the label `user=alice`. But _this_ policy:
+
+```yaml
+ ...
+ ingress:
+ - from:
+ - namespaceSelector:
+ matchLabels:
+ user: alice
+ - podSelector:
+ matchLabels:
+ role: client
+ ...
+```
+
+contains two elements in the `from` array, and allows connections from Pods in the local Namespace with the label `role=client`, _or_ from any Pod in any namespace with the label `user=alice`.
+
+When in doubt, use `kubectl describe` to see how Kubernetes has interpreted the policy.
+
+**ipBlock**: This selects particular IP CIDR ranges to allow as ingress sources or egress destinations. These should be cluster-external IPs, since Pod IPs are ephemeral and unpredictable.
+
+Cluster ingress and egress mechanisms often require rewriting the source or destination IP of packets.
+
+In cases where this happens, it is not defined whether this happens before or after NetworkPolicy processing, and the behavior may be different for different combinations of network plugin, cloud provider, `Service` implementation, etc.
+
+In the case of ingress, this means that in some cases you may be able to filter incoming packets based on the actual original source IP, while in other cases, the "source IP" that the NetworkPolicy acts on may be the IP of a `LoadBalancer` or of the Pod's node, etc.
+
+For egress, this means that connections from pods to `Service` IPs that get rewritten to cluster-external IPs may or may not be subject to `ipBlock`-based policies.
+
+
+## Default policies
+
+By default, if no policies exist in a namespace, then all ingress and egress traffic is allowed to and from pods in that namespace. The following examples let you change the default behavior in that namespace.
+
+### Default deny all ingress traffic
+
+You can create a "default" ingress isolation policy for a namespace by creating a NetworkPolicy that selects all pods but does not allow any ingress traffic to those pods.
+
+
+```yaml
+---
+#network-policy-default-deny-ingress-yaml
+
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: default-deny-ingress
+spec:
+ podSelector: {}
+ policyTypes:
+ - Ingress
+```
+
+This ensures that even pods that aren't selected by any other NetworkPolicy will still be isolated for ingress. This policy does not affect isolation for egress from any pod.
+
+### Allow all ingress traffic
+
+If you want to allow all incoming connections to all pods in a namespace, you can create a policy that explicitly allows that.
+
+
+```yaml
+---
+#network-policy-allow-all-ingress-yaml
+
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: allow-all-ingress
+spec:
+ podSelector: {}
+ ingress:
+ - {}
+ policyTypes:
+ - Ingress
+```
+
+With this policy in place, no additional policy or policies can cause any incoming connection to those pods to be denied. This policy has no effect on isolation for egress from any pod.
+
+### Default deny all egress traffic
+
+You can create a "default" egress isolation policy for a namespace by creating a NetworkPolicy that selects all pods but does not allow any egress traffic from those pods.
+
+
+```yaml
+---
+#network-policy-default-deny-egress-yaml
+
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: default-deny-egress
+spec:
+ podSelector: {}
+ policyTypes:
+ - Egress
+```
+
+This ensures that even pods that aren't selected by any other NetworkPolicy will not be allowed egress traffic. This policy does not change the ingress isolation behavior of any pod.
+
+### Allow all egress traffic
+
+If you want to allow all connections from all pods in a namespace, you can create a policy that explicitly allows all outgoing connections from pods in that namespace.
+
+
+```yaml
+---
+#network-policy-allow-all-egress-yaml
+
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: allow-all-egress
+spec:
+ podSelector: {}
+ egress:
+ - {}
+ policyTypes:
+ - Egress
+```
+
+With this policy in place, no additional policy or policies can cause any outgoing connection from those pods to be denied. This policy has no effect on isolation for ingress to any pod.
+
+### Default deny all ingress and all egress traffic
+
+You can create a "default" policy for a namespace which prevents all ingress AND egress traffic by creating the following NetworkPolicy in that namespace.
+
+
+```yaml
+---
+#network-policy-default-deny-all-yaml
+
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: default-deny-all
+spec:
+ podSelector: {}
+ policyTypes:
+ - Ingress
+ - Egress
+```
+
+This ensures that even pods that aren't selected by any other NetworkPolicy will not be allowed ingress or egress traffic.
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-allow-all-egress-yaml.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-allow-all-egress-yaml.yaml
new file mode 100644
index 00000000..1a79d115
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-allow-all-egress-yaml.yaml
@@ -0,0 +1,10 @@
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: allow-all-egress
+spec:
+ podSelector: {}
+ egress:
+ - {}
+ policyTypes:
+ - Egress
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-allow-all-ingress-yaml.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-allow-all-ingress-yaml.yaml
new file mode 100644
index 00000000..9f61a216
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-allow-all-ingress-yaml.yaml
@@ -0,0 +1,10 @@
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: allow-all-ingress
+spec:
+ podSelector: {}
+ ingress:
+ - {}
+ policyTypes:
+ - Ingress
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-default-deny-all-yaml.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-default-deny-all-yaml.yaml
new file mode 100644
index 00000000..050dbfed
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-default-deny-all-yaml.yaml
@@ -0,0 +1,9 @@
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: default-deny-all
+spec:
+ podSelector: {}
+ policyTypes:
+ - Ingress
+ - Egress
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-default-deny-egress-yaml.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-default-deny-egress-yaml.yaml
new file mode 100644
index 00000000..2871da61
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-default-deny-egress-yaml.yaml
@@ -0,0 +1,8 @@
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: default-deny-egress
+spec:
+ podSelector: {}
+ policyTypes:
+ - Egress
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-default-deny-ingress-yaml.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-default-deny-ingress-yaml.yaml
new file mode 100644
index 00000000..1375b1f2
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/network-policy-default-deny-ingress-yaml.yaml
@@ -0,0 +1,8 @@
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: default-deny-ingress
+spec:
+ podSelector: {}
+ policyTypes:
+ - Ingress
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/networkpolicy.yaml b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/networkpolicy.yaml
new file mode 100644
index 00000000..ad9ee08a
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/Networking/Network Policies/networkpolicy.yaml
@@ -0,0 +1,34 @@
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: test-network-policy
+ namespace: default #change namespace
+spec:
+ podSelector:
+ matchLabels:
+ role: db
+ policyTypes:
+ - Ingress
+ - Egress
+ ingress:
+ - from:
+ - ipBlock:
+ cidr: 172.17.0.0/16
+ except:
+ - 172.17.1.0/24
+ - namespaceSelector:
+ matchLabels:
+ project: myproject
+ - podSelector:
+ matchLabels:
+ role: frontend
+ ports:
+ - protocol: TCP
+ port: 6379
+ egress:
+ - to:
+ - ipBlock:
+ cidr: 10.0.0.0/24
+ ports:
+ - protocol: TCP
+ port: 5978
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/NodePort-service.yaml b/Kubernetes-Basic-2-Days/Modules/NodePort-service.yaml
new file mode 100644
index 00000000..479e3f6a
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/NodePort-service.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: my-service
+spec:
+ type: NodePort
+ selector:
+ app.kubernetes.io/name: MyApp
+ ports:
+ # By default and for convenience, the `targetPort` is set to the same value as the `port` field.
+ - port: 80
+ targetPort: 80
+ # Optional field
+ # By default and for convenience, the Kubernetes control plane will allocate a port from a range (default: 30000-32767)
+ nodePort: 30007
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/README.md b/Kubernetes-Basic-2-Days/Modules/README.md
new file mode 100644
index 00000000..f8500105
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/README.md
@@ -0,0 +1,379 @@
+Table of Contents
+=================
+
+ * [Labels and Selectors](#labels-and-selectors)
+ * [Label selectors](#label-selectors)
+ * [Equality-based requirement](#equality-based-requirement)
+ * [Set-based requirement](#set-based-requirement)
+ * [Deployments](#deployments)
+ * [Strategy](#strategy)
+ * [Recreate Deployment](#recreate-deployment)
+ * [Rolling Update Deployment](#rolling-update-deployment)
+ * [Updating a Deployment](#updating-a-deployment)
+ * [Checking Rollout History of a Deployment](#checking-rollout-history-of-a-deployment)
+ * [Rolling Back to a Previous Revision](#rolling-back-to-a-previous-revision)
+ * [Replicasets](#replicasets)
+ * [Service](#service)
+ * [Namespace](#namespace)
+
+## Labels and Selectors
+
+Labels are key/value pairs that are attached to objects, such as pods.
+
+Each object can have a set of key/value labels defined. Each Key must be unique for a given object.
+
+```
+"metadata": {
+ "labels": {
+ "key1" : "value1",
+ "key2" : "value2"
+ }
+}
+
+```
+Example labels:
+
+- "`release" : "stable"`, `"release" : "canary"`
+- `"environment" : "dev"`, `"environment" : "qa"`, `"environment" : "production"`
+- `"tier" : "frontend"`, `"tier" : "backend"`, `"tier" : "cache"`
+- `"partition" : "customerA"`, `"partition" : "customerB"`
+- `"track" : "daily"`, `"track" : "weekly"`
+
+## Label selectors
+
+- The API currently supports two types of selectors: **equality-based** and **set-based**.
+- A label selector can be made of multiple **requirements** which are comma-separated.
+- In the case of multiple requirements, all must be satisfied so the comma separator acts as a logical AND (`&&`) operator.
+
+### Equality-based requirement
+
+_Equality_- or _inequality-based_ requirements allow filtering by label keys and values.
+
+Matching objects must satisfy all of the specified label constraints, though they may have additional labels as well.
+
+Three kinds of operators are admitted `=`,`==`,`!=`.
+
+The first two represent _equality_ (and are synonyms), while the latter represents _inequality_.
+
+For example:
+
+```
+environment = production
+tier != frontend
+```
+The former selects all resources with key equal to `environment` and value equal to `production`. The latter selects all resources with key equal to `tier` and value distinct from `frontend`, and all resources with no labels with the `tier` key. One could filter for resources in production excluding `frontend` using the comma operator: `environment=production,tier!=frontend`
+
+
+### Set-based requirement
+
+_Set-based_ label requirements allow filtering keys according to a set of values.
+
+Three kinds of operators are supported: `in`,`notin` and `exists` (only the key identifier).
+
+For example:
+```
+environment in (production, qa)
+tier notin (frontend, backend)
+partition
+!partition
+```
+
+- The first example selects all resources with key equal to `environment` and value equal to `production` or `qa`.
+
+
+- The second example selects all resources with key equal to `tier` and values other than `frontend` and `backend`, and all resources with no labels with the tier key.
+
+
+- The third example selects all resources including a label with key partition; no values are checked.
+
+
+- The fourth example selects all resources without a label with key partition; no values are checked.
+
+
+Similarly the comma separator acts as an _AND_ operator.
+
+So filtering resources with a `partition` key (no matter the value) and with `environment` different than `qa` can be achieved using `partition,environment notin (qa)`.
+
+The _set-based_ label selector is a general form of equality since `environment=production` is equivalent to `environment in (production)`; similarly for `!=` and `notin`.
+
+Set-based requirements can be mixed with _equality-based_ requirements. For example:
+
+`partition in (customerA, customerB),environment!=qa`.
+
+
+Both label selector styles can be used to list or watch resources via a REST client. For example, targeting `apiserver` with kubectl and using `equality-based` one may write:
+
+```
+kubectl get pods -l environment=production,tier=frontend
+```
+or using set-based requirements:
+
+```
+kubectl get pods -l 'environment in (production),tier in (frontend)'
+```
+
+As already mentioned **set-based** requirements are more expressive. For instance, they can implement the **OR** operator on values:
+
+```
+kubectl get pods -l 'environment in (production, qa)'
+```
+
+or restricting negative matching via exists operator:
+
+```
+kubectl get pods -l 'environment,environment notin (frontend)'
+```
+
+## Deployments
+
+### Strategy
+
+`.spec.strategy` specifies the strategy used to replace old Pods by new ones. `.spec.strategy.type` can be "Recreate" or "RollingUpdate". "RollingUpdate" is the default value.
+
+#### Recreate Deployment
+
+All existing Pods are killed before new ones are created when `.spec.strategy.type==Recreate`.
+
+#### Rolling Update Deployment
+
+Replaces pods running the old version of the application with the new version, one by one, without downtime to the cluster.
+
+The Deployment updates Pods in a rolling update fashion when `.spec.strategy.type==RollingUpdate`.
+
+## Updating a Deployment
+
+Follow the steps given below to update your Deployment:
+
+Let's update the nginx Pods to use the `nginx:1.16.1` image instead of the `nginx:1.14.2` image.
+
+```
+kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
+```
+
+or use the following command:
+
+```
+kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
+```
+
+The output is similar to:
+
+```
+deployment.apps/nginx-deployment image updated
+```
+
+Alternatively, you can `edit` the Deployment and change `.spec.template.spec.containers[0].image` from `nginx:1.14.2` to `nginx:1.16.1`:
+
+```
+kubectl edit deployment/nginx-deployment
+```
+
+The output is similar to:
+
+```
+deployment.apps/nginx-deployment edited
+```
+
+To see the rollout status, run:
+
+```
+kubectl rollout status deployment/nginx-deployment
+```
+
+The output is similar to this:
+
+```
+Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
+```
+
+or
+
+```
+deployment "nginx-deployment" successfully rolled out
+```
+
+Get more details on your updated Deployment:
+
+After the rollout succeeds, you can view the Deployment by running
+
+```
+kubectl get deployments
+```
+
+The output is similar to this:
+```
+NAME READY UP-TO-DATE AVAILABLE AGE
+nginx-deployment 3/3 3 3 36s
+```
+
+Run `kubectl get rs` to see that the Deployment updated the Pods by creating a new ReplicaSet and scaling it up to 3 replicas, as well as scaling down the old ReplicaSet to 0 replicas.
+
+kubectl get rs
+The output is similar to this:
+
+```
+NAME DESIRED CURRENT READY AGE
+nginx-deployment-1564180365 3 3 3 6s
+nginx-deployment-2035384211 0 0 0 36s
+```
+
+Running get pods should now show only the new Pods:
+
+```
+kubectl get pods
+```
+
+The output is similar to this:
+
+```
+NAME READY STATUS RESTARTS AGE
+nginx-deployment-1564180365-khku8 1/1 Running 0 14s
+nginx-deployment-1564180365-nacti 1/1 Running 0 14s
+nginx-deployment-1564180365-z9gth 1/1 Running 0 14s
+```
+
+Next time you want to update these Pods, you only need to update the Deployment's Pod template again.
+
+
+Get details of your Deployment:
+
+```
+kubectl describe deployments
+```
+
+#### Checking Rollout History of a Deployment
+
+Sometimes, you may want to rollback a Deployment; for example, when the Deployment is not stable, such as crash looping.
+
+By default, all of the Deployment's rollout history is kept in the system so that you can rollback anytime you want (you can change that by modifying revision history limit).
+
+First, check the revisions of this Deployment:
+
+```
+kubectl rollout history deployment/nginx-deployment
+```
+
+To see the details of each revision, run:
+
+```
+kubectl rollout history deployment/nginx-deployment --revision=2
+```
+
+#### Rolling Back to a Previous Revision
+
+Now you've decided to undo the current rollout and rollback to the previous revision:
+
+```
+kubectl rollout undo deployment/nginx-deployment
+```
+
+Alternatively, you can rollback to a specific revision by specifying it with `--to-revision`:
+
+```
+kubectl rollout undo deployment/nginx-deployment --to-revision=2
+```
+
+## Replicasets
+
+A ReplicaSet's purpose is to maintain a stable set of replica Pods running at any given time.
+
+As such, it is often used to guarantee the availability of a specified number of identical Pods.
+
+Directly update the replicas field in the live configuration by using kubectl scale. This does not use kubectl apply:
+
+```
+kubectl scale deployment/nginx-deployment --replicas=2
+```
+
+Print the live configuration using kubectl get:
+
+```
+kubectl get deployment nginx-deployment -o yaml
+```
+
+The output shows that the replicas field has been set to 2.
+
+It is recommended using Deployments instead of directly using ReplicaSets, unless you require custom update orchestration or don't require updates at all.
+
+This actually means that you may never need to manipulate ReplicaSet objects: use a Deployment instead, and define your application in the spec section.
+
+```
+kubectl apply -f frontend.yaml
+```
+
+You can then get the current ReplicaSets deployed:
+```
+kubectl get rs
+```
+
+To check on the state of the ReplicaSet:
+
+```
+kubectl describe rs/frontend
+```
+
+To check for the Pods brought up:
+
+```
+kubectl get pods
+```
+
+## Service
+
+An abstract way to expose an application running on a set of Pods as a network service.
+
+Kubernetes ServiceTypes allow you to specify what kind of Service you want. The default is ClusterIP.
+
+Type values and their behaviors are:
+
+- `ClusterIP`: Exposes the Service on a cluster-internal IP. Choosing this value makes the Service only reachable from within the cluster. This is the default `ServiceType`.
+
+- `NodePort`: Exposes the Service on each Node's IP at a static port (the `NodePort`). A `ClusterIP` Service, to which the `NodePort` Service routes, is automatically created. You'll be able to contact the `NodePort` Service, from outside the cluster, by requesting :.
+
+- `LoadBalancer`: Exposes the Service externally using a cloud provider's load balancer. `NodePort` and `ClusterIP` Services, to which the external load balancer routes, are automatically created.
+
+- `ExternalName`: Maps the Service to the contents of the `externalName` field (e.g. `foo.bar.example.com`), by returning a `CNAME` record with its value. No proxying of any kind is set up.
+
+
+## Namespace
+
+In Kubernetes, _namespaces_ provides a mechanism for isolating groups of resources within a single cluster.
+
+Names of resources need to be unique within a namespace, but not across namespaces.
+
+Namespace-based scoping is applicable only for namespaced objects _(e.g. Deployments, Services, etc)_ and not for cluster-wide objects _(e.g. StorageClass, Nodes, PersistentVolumes, etc)_.
+
+```
+kubectl create namespace yellow
+```
+```
+kubectl create namespace blue
+```
+
+```
+kubectl create namespace red
+```
+
+```
+kubectl create namespace white
+```
+
+To count the namespaces use below command:
+
+```
+kubectl get namespaces --no-headers | wc -l
+```
+
+To find the nginx pod from all the namespaces:
+
+```
+kubectl get pods --all-namespaces | grep nginx
+```
+
+Below command will show you the yellow namespace service:
+
+```
+kubectl --namespaces yellow get svc
+```
+
+Reference link: [Namespace Concepts](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/)
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/deployment.yaml b/Kubernetes-Basic-2-Days/Modules/deployment.yaml
new file mode 100644
index 00000000..5b3c684b
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/deployment.yaml
@@ -0,0 +1,19 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: nginx-deployment
+spec:
+ selector:
+ matchLabels:
+ app: nginx
+ minReadySeconds: 5
+ template:
+ metadata:
+ labels:
+ app: nginx
+ spec:
+ containers:
+ - name: nginx
+ image: nginx:1.14.2
+ ports:
+ - containerPort: 80
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/frontend.yaml b/Kubernetes-Basic-2-Days/Modules/frontend.yaml
new file mode 100644
index 00000000..38cba7cd
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/frontend.yaml
@@ -0,0 +1,21 @@
+apiVersion: apps/v1
+kind: ReplicaSet
+metadata:
+ name: frontend
+ labels:
+ app: guestbook
+ tier: frontend
+spec:
+ # modify replicas according to your case
+ replicas: 3
+ selector:
+ matchLabels:
+ tier: frontend
+ template:
+ metadata:
+ labels:
+ tier: frontend
+ spec:
+ containers:
+ - name: php-redis
+ image: gcr.io/google_samples/gb-frontend:v3
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/CLI/README.md b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/CLI/README.md
new file mode 100644
index 00000000..b16233bf
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/CLI/README.md
@@ -0,0 +1,705 @@
+
+# Using the CLI
+The Kubernetes client, `kubectl` is the primary method of interacting with a Kubernetes cluster. Getting to know it is essential to using Kubernetes itself.
+
+
+## Index
+- [Syntax Structure](#syntax-structure)
+- [Context and kubeconfig](#context-and-kubeconfig)
+ - [`kubectl config`](#kubectl-config)
+ - [Exercise: Using Contexts](#exercise-using-contexts)
+ - [Kubectl Basics](#kubectl-basics)
+ - [`kubectl get`](#kubectl-get)
+ - [`kubectl create`](#kubectl-create)
+ - [`kubectl apply`](#kubectl-apply)
+ - [`kubectl edit`](#kubectl-edit)
+ - [`kubectl delete`](#kubectl-delete)
+ - [`kubectl describe`](#kubectl-describe)
+ - [`kubectl logs`](#kubectl-logs)
+ - [Exercise: The Basics](#exercise-the-basics)
+- [Accessing the Cluster](#accessing-the-cluster)
+ - [`kubectl exec`](#kubectl-exec)
+ - [Exercise: Executing Commands within a Remote Pod](#exercise-executing-commands-within-a-remote-pod)
+ - [`kubectl proxy`](#kubectl-proxy)
+ - [Exercise: Using the Proxy](#exercise-using-the-proxy)
+ - [Cleaning up](#cleaning-up)
+ - [Helpful Resources](#helpful-resources)
+
+---
+
+# Syntax Structure
+
+`kubectl` uses a common syntax for all operations in the form of:
+
+```
+kubectl [TYPE] [NAME] [flags]
+```
+
+* **command** - Specifies the operation that you want to perform on one or more resources, for example `create`, `get`, `describe`, `delete`.
+* **type** - The resource type or object.
+* **name** - The name of the resource or object.
+* **flags** - Optional flags to pass to the command.
+
+**Examples**
+```
+kubectl create -f mypod.yaml
+```
+
+```
+kubectl get pods
+```
+
+```
+kubectl get pod mypod
+```
+
+```
+kubectl delete pod mypod
+```
+
+---
+
+[Back to Index](#index)
+
+---
+---
+
+
+# Context and kubeconfig
+`kubectl` allows a user to interact with and manage multiple Kubernetes clusters. To do this, it requires what is known
+as a context. A context consists of a combination of `cluster`, `namespace` and `user`.
+
+* **cluster** - A friendly name, server address, and certificate for the Kubernetes cluster.
+* **namespace (optional)** - The logical cluster or environment to use. If none is provided, it will use the default
+`default` namespace.
+* **user** - The credentials used to connect to the cluster. This can be a combination of client certificate and key, username/password, or token.
+
+These contexts are stored in a local yaml based config file referred to as the `kubeconfig`. For \*nix based
+systems, the `kubeconfig` is stored in `$HOME/.kube/config` for Windows, it can be found in
+`%USERPROFILE%/.kube/config`
+
+This config is viewable without having to view the file directly.
+
+**Command**
+
+```
+kubectl config view
+```
+
+the output might be from a single kubeconfig file, or it might be the result of merging several kubeconfig files.
+
+Here are the rules that `kubectl` uses when it merges kubeconfig files:
+
+1. If the `--kubeconfig` flag is set, use only the specified file. Do not merge. Only one instance of this flag is allowed.
+
+ Otherwise, if the `KUBECONFIG` environment variable is set, use it as a list of files that should be merged. Merge the files listed in the `KUBECONFIG` environment variable according to these rules:
+
+ - Ignore empty filenames.
+ - Produce errors for files with content that cannot be deserialized.
+ - The first file to set a particular value or map key wins.
+ - Never change the value or map key. Example: Preserve the context of the first file to set `current-context`. Example: If two files specify a `red-user`, use only values from the first file's `red-user`. Even if the second file has non-conflicting entries under `red-user`, discard them.
+
+ Otherwise, use the default kubeconfig file, `$HOME/.kube/config`, with no merging.
+
+2. Determine the context to use based on the first hit in this chain:
+
+ 1. Use the `--context` command-line flag if it exists.
+ 2. Use the `current-context` from the merged kubeconfig files.
+
+ An empty context is allowed at this point.
+
+3. Determine the cluster and user. At this point, there might or might not be a context. Determine the cluster and user based on the first hit in this chain, which is run twice: once for user and once for cluster:
+
+ 1. Use a command-line flag if it exists: `--user` or `--cluster`.
+ 2. If the context is non-empty, take the user or cluster from the context.
+
+ The user and cluster can be empty at this point.
+
+4. Determine the actual cluster information to use. At this point, there might or might not be cluster information. Build each piece of the cluster information based on this chain; the first hit wins:
+
+ 1. Use command line flags if they exist: `--server`, `--certificate-authority`, `--insecure-skip-tls-verify`.
+ 2. If any cluster information attributes exist from the merged kubeconfig files, use them.
+ 3. If there is no server location, fail.
+
+5. Determine the actual user information to use. Build user information using the same rules as cluster information, except allow only one authentication technique per user:
+
+ 1. Use command line flags if they exist: `--client-certificate`, `--client-key`, `--username`, `--password`, `--token`.
+ 2. Use the `user` fields from the merged kubeconfig files.
+ 3. If there are two conflicting techniques, fail.
+
+6. For any information still missing, use default values and potentially prompt for authentication information.
+---
+
+### `kubectl config`
+
+Managing all aspects of contexts is done via the `kubectl config` command. Some examples include:
+* See the active context with
+
+```
+kubectl config current-context
+```
+* Get a list of available contexts with
+
+```
+kubectl config get-contexts
+```
+* Switch to using another context with the
+```
+kubectl config use-context
+```
+
+* Add a new context with
+```
+kubectl config set-context --cluster= --user= --namespace=
+```
+
+
+There can be quite a few specifics involved when adding a context, for the available options, please see the [Configuring Multiple Clusters](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) Kubernetes documentation.
+
+---
+
+### Exercise: Using Contexts
+
+
+**Objective:** Create a new context called `kind-dev` and switch to it.
+
+---
+
+1. View the current contexts.
+```
+kubectl config get-contexts
+```
+
+2. Create a new context called `kind-dev` within the `kind-kind` cluster with the `dev` namespace, as the
+`kind-kind` user.
+```
+kubectl config set-context kind-dev --cluster=kind-kind --user=kind-kind --namespace=dev
+```
+
+3. View the newly added context.
+```
+kubectl config get-contexts
+```
+
+4. Switch to the `kind-dev` context using `use-context`.
+```
+kubectl config use-context kind-dev
+```
+
+5. View the current active context.
+```
+kubectl config current-context
+```
+
+---
+
+**Summary:** Understanding and being able to switch between contexts is a base fundamental skill required by every Kubernetes user. As more clusters and namespaces are added, this can become unwieldy. Installing a helper
+application such as [kubectx](https://github.com/ahmetb/kubectx) can be quite helpful. Kubectx allows a user to quickly
+switch between contexts and namespaces without having to use the full `kubectl config use-context` command. Setting up the alias for the contexts is another workaround.
+
+---
+
+[Back to Index](#index)
+
+---
+---
+
+## Kubectl Basics
+
+
+There are several `kubectl` commands that are frequently used for any sort of day-to-day operations. `get`, `create`,
+`apply`, `delete`, `describe`, and `logs`. Other commands can be listed simply with `kubectl --help`, or
+`kubectl --help`.
+
+
+---
+
+### `kubectl get`
+
+
+`kubectl get` fetches and lists objects of a certain type or a specific object itself. It also supports outputting the
+information in several different useful formats including: json, yaml, wide (additional columns), or name
+(names only) via the `-o` or `--output` flag.
+
+**Command**
+```
+kubectl get
+kubectl get
+kubectl get -o
+```
+
+**Examples**
+```
+kubectl get namespaces
+```
+
+```Output
+NAME STATUS AGE
+default Active 4h
+kube-public Active 4h
+kube-system Active 4h
+```
+```
+kubectl get pod mypod -o wide
+```
+
+```Output
+NAME READY STATUS RESTARTS AGE IP NODE
+mypod 1/1 Running 0 5m 172.17.0.6 kind-control-plane
+```
+
+---
+
+### `kubectl create`
+
+
+`kubectl create` creates an object from the commandline (`stdin`) or a supplied json/yaml manifest. The manifests can be specified with the `-f` or `--filename` flag that can point to either a file, or a directory containing multiple manifests.
+
+**Command**
+```
+kubectl create
+kubectl create -f
+```
+
+**Examples**
+```
+kubectl create namespace dev
+namespace "dev" created
+```
+
+```
+kubectl create -f manifests/mypod.yaml
+pod "mypod" created
+```
+
+---
+
+### `kubectl apply`
+
+
+`kubectl apply` is similar to `kubectl create`. It will essentially update the resource if it is already created, or simply create it if does not yet exist. When it updates the config, it will save the previous version of it in an `annotation` on the created object itself.
+
+**WARNING:** If the object was not created initially with `kubectl apply` it's updating behavior will act as a two-way diff.
+
+For more information on this, please see the [kubectl apply](https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#kubectl-apply) documentation.
+
+Just like `kubectl create` it takes a json or yaml manifest with the `-f` flag or accepts input from `stdin`.
+
+**Command**
+```
+kubectl apply -f
+```
+
+**Examples**
+```
+kubectl apply -f manifests/mypod.yaml
+```
+
+---
+
+### `kubectl edit`
+
+
+`kubectl edit` modifies a resource in place without having to apply an updated manifest. It fetches a copy of the desired object and opens it locally with the configured text editor, set by the `KUBE_EDITOR` or `EDITOR` Environment Variables.
+
+This command is useful for troubleshooting, but should be avoided in production scenarios as the changes will essentially be untracked.
+
+**Command**
+```
+kubectl edit
+```
+
+**Examples**
+```
+kubectl edit pod mypod
+```
+
+```
+kubectl edit service myservice
+```
+
+---
+
+### `kubectl delete`
+
+
+`kubectl delete` deletes the object from Kubernetes.
+
+**Command**
+```
+kubectl delete
+```
+
+**Examples**
+```
+kubectl delete pod mypod
+pod "mypod" deleted
+```
+
+---
+
+### `kubectl describe`
+
+
+`kubectl describe` lists detailed information about the specific Kubernetes object. It is a very helpful
+troubleshooting tool.
+
+**Command**
+```
+kubectl describe
+kubectl describe
+```
+
+**Examples**
+```
+kubectl describe pod mypod
+```
+
+```Output
+Name: mypod
+Namespace: dev
+Node: kind-control-plane/192.168.99.100
+Start Time: Fri, 21 Oct 2022 3:12:43 -0100
+Labels:
+Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"mypod","namespace":"dev"},"spec":{"containers":[{"image":...
+Status: Running
+IP: 172.17.0.6
+Containers:
+ nginx:
+ Container ID: docker://5a0c100de6599300b1565e73e64e8917f9a4f4b06325dc4890aad980d582cf04
+ Image: nginx:stable-alpine
+ Image ID: docker-pullable://nginx@sha256:db5acc22920799fe387a903437eb89387607e5b3f63cf0f4472ac182d7bad644
+ Port: 80/TCP
+ State: Running
+ Started: Fri, 21 Oct 2022 3:12:43 -0100
+ Ready: True
+ Restart Count: 0
+ Environment:
+ Mounts:
+ /var/run/secrets/kubernetes.io/serviceaccount from default-token-s2xd7 (ro)
+Conditions:
+ Type Status
+ Initialized True
+ Ready True
+ PodScheduled True
+Volumes:
+ default-token-s2xd7:
+ Type: Secret (a volume populated by a Secret)
+ SecretName: default-token-s2xd7
+ Optional: false
+QoS Class: BestEffort
+Node-Selectors:
+Tolerations:
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Scheduled 5s default-scheduler Successfully assigned mypod to kind-control-plane
+ Normal SuccessfulMountVolume 5s kubelet, kind-control-plane MountVolume.SetUp succeeded for volume "default-token-s2xd7"
+ Normal Pulled 5s kubelet, kind-control-plane Container image "nginx:stable-alpine" already present on machine
+ Normal Created 5s kubelet, kind-control-plane Created container
+ Normal Started 5s kubelet, kind-control-plane Started container
+ ```
+
+---
+
+### `kubectl logs`
+
+
+`kubectl logs` outputs the combined `stdout` and `stderr` logs from a pod. If more than one container exist in a
+`pod` the `-c` flag is used and the container name must be specified.
+
+**Command**
+```
+kubectl logs
+kubectl logs -c
+```
+
+**Examples**
+```
+kubectl logs mypod
+```
+
+```
+172.17.0.1 - - [24/Oct/2022:16:14:15 +0100] "GET / HTTP/1.1" 200 612 "-" "curl/7.57.0" "-"
+172.17.0.1 - - [24/Oct/2022:16:14:15 +0100] "GET / HTTP/1.1" 200 612 "-" "curl/7.57.0" "-"
+```
+
+---
+
+### Exercise: The Basics
+
+
+**Objective:** Explore the basics. Create a namespace, a pod, then use the `kubectl` commands to describe and delete what was created.
+
+**NOTE:** You should still be using the `kind-dev` context created earlier.
+
+---
+
+1) Create the `dev` namespace.
+```
+kubectl create namespace dev
+```
+
+2) Apply the manifest `manifests/mypod.yaml`.
+```
+kubectl apply -f manifests/mypod.yaml
+```
+
+3) Get the yaml output of the created pod `mypod`.
+```
+kubectl get pod mypod -o yaml
+```
+
+4) Describe the pod `mypod`.
+```
+kubectl describe pod mypod
+```
+
+5) Clean up the pod by deleting it.
+```
+kubectl delete pod mypod
+```
+
+---
+
+**Summary:** The `kubectl` _"CRUD"_ commands are used frequently when interacting with a Kubernetes cluster. These simple tasks become 2nd nature as more experience is gained.
+
+---
+
+[Back to Index](#index)
+
+---
+---
+
+# Accessing the Cluster
+
+`kubectl` provides several mechanisms for accessing resources within the cluster remotely. For this tutorial, the focus will be on using `kubectl exec` to get a remote shell within a container, and `kubectl proxy` to gain access to the services exposed through the API proxy.
+
+---
+
+### `kubectl exec`
+
+
+`kubectl exec` executes a command within a Pod and can optionally spawn an interactive terminal within a remote
+container. When more than one container is present within a Pod, the `-c` or `--container` flag is required, followed
+by the container name.
+
+If an interactive session is desired, the `-i` (`--stdin`) and `-t` (`--tty`) flags must be supplied.
+
+**Command**
+```
+kubectl exec --
+```
+
+```
+kubectl exec -c --
+```
+
+```
+kubectl exec -i -t -c --
+```
+
+```
+kubectl exec -it -c --
+```
+
+
+**Example**
+```
+kubectl exec mypod -c nginx -- printenv
+```
+
+```
+PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+HOSTNAME=mypod
+KUBERNETES_SERVICE_PORT_HTTPS=443
+KUBERNETES_PORT=tcp://10.96.0.1:443
+KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
+KUBERNETES_PORT_443_TCP_PROTO=tcp
+KUBERNETES_PORT_443_TCP_PORT=443
+KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
+KUBERNETES_SERVICE_HOST=10.96.0.1
+KUBERNETES_SERVICE_PORT=443
+NGINX_VERSION=1.12.2
+HOME=/root
+
+```
+
+```
+kubectl exec -i -t mypod -c nginx -- /bin/sh
+/ #
+/ # cat /etc/alpine-release
+3.5.2
+```
+
+---
+
+### Exercise: Executing Commands within a Remote Pod
+
+
+**Objective:** Use `kubectl exec` to both initiate commands and spawn an interactive shell within a Pod.
+
+---
+
+1) If not already created, create the Pod `mypod` from the manifest `manifests/mypod.yaml`.
+```
+kubectl create -f manifests/mypod.yaml
+```
+
+2) Wait for the Pod to become ready (`running`).
+```
+kubectl get pods --watch
+```
+
+3) Use `kubectl exec` to `cat` the file `/etc/os-release`.
+```
+kubectl exec mypod -- cat /etc/os-release
+```
+It should output the contents of the `os-release` file.
+
+4) Now use `kubectl exec` and supply the `-i -t` flags to spawn a shell session within the container.
+```
+kubectl exec -i -t mypod -- /bin/sh
+```
+If executed correctly, it should drop you into a new shell session within the nginx container.
+
+5) use `ps aux` to view the current processes within the container.
+```
+ps aux
+```
+There should be two nginx processes along with a `/bin/sh` process representing your interactive shell.
+
+6) Exit out of the container simply by typing `exit`.
+7) With that the shell process will be terminated and the only running processes within the container should once again be nginx and its worker process.
+
+---
+
+**Summary:** `kubectl exec` is not often used, but is an important skill to be familiar with when it comes to Pod debugging.
+
+---
+
+### `kubectl proxy`
+
+
+`kubectl proxy` enables access to both the Kubernetes API-Server and to resources running within the cluster securely using `kubectl`. By default it creates a connection to the API-Server that can be accessed at `127.0.0.1:8001` or an alternative port by supplying the `-p` or `--port` flag.
+
+
+**Command**
+```
+kubectl proxy
+kubectl proxy --port=
+```
+
+**Examples**
+```
+kubectl proxy
+```
+
+```Output
+Starting to serve on 127.0.0.1:8001
+
+
+```
+
+```
+curl 127.0.0.1:8001/version
+```
+
+```Output
+{
+ "major": "",
+ "minor": "",
+ "gitVersion": "v1.9.0",
+ "gitCommit": "925c127ec6b946659ad0fd596fa959be43f0cc05",
+ "gitTreeState": "clean",
+ "buildDate": "2022-10-24T16:04:08Z",
+ "goVersion": "go1.9.1",
+ "compiler": "gc",
+ "platform": "linux/amd64"
+}
+```
+
+The Kubernetes API-Server has the built in capability to proxy to running services or pods within the cluster. This ability in conjunction with the `kubectl proxy` command allows a user to access those services or pods without having to expose them outside of the cluster.
+
+```
+http:///api/v1/namespaces///[:port_name]/proxy
+```
+* **proxy_address** - The local proxy address - `127.0.0.1:8001`
+* **namespace** - The namespace owning the resources to proxy to.
+* **service|pod** - The type of resource you are trying to access, either `service` or `pod`.
+* **service_name|pod_name** - The name of the `service` or `pod` to be accessed.
+* **[:port]** - An optional port to proxy to. Will default to the first one exposed.
+
+**Example**
+```
+http://127.0.0.1:8001/api/v1/namespaces/default/pods/mypod/proxy/
+```
+
+---
+
+### Exercise: Using the Proxy
+
+
+**Objective:** Examine the capabilities of the proxy by accessing a pod's exposed ports.
+
+---
+
+1) Create the Pod `mypod` from the manifest `manifests/mypod.yaml`. (if not created previously)
+```
+kubectl create -f manifests/mypod.yaml
+```
+
+2) Start the `kubectl proxy` with the defaults.
+```
+kubectl proxy
+```
+
+3) Access the Pod through the proxy.
+```
+http://127.0.0.1:8001/api/v1/namespaces/dev/pods/mypod/proxy/
+```
+You should see the "Welcome to nginx!" page.
+
+---
+
+**Summary:** Being able to access the exposed Pods and Services within a cluster without having to consume an external IP, or create firewall rules is an incredibly useful tool for troubleshooting cluster services.
+
+---
+
+[Back to Index](#index)
+
+---
+---
+
+## Cleaning up
+**NOTE:** If you are proceeding with the next tutorials, simply delete the pod with:
+```
+kubectl delete pod mypod
+```
+The namespace and context will be reused.
+
+To remove everything that was created in this tutorial, execute the following commands:
+```
+kubectl delete namespace dev
+```
+
+```
+kubectl config delete-context kind-dev
+```
+
+---
+
+[Back to Index](#index)
+
+---
+---
+
+### Helpful Resources
+* [kubectl Overview](https://kubernetes.io/docs/reference/kubectl/overview/)
+* [kubectl Cheat Sheet](https://kubernetes.io/docs/reference/kubectl/cheatsheet/)
+* [kubectl Reference](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands)
+* [Accessing Clusters](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/)
+* [Using the CLI](https://github.com/AbstractInfrastructure/k8s-intro-tutorials/tree/master/cli)
+
+
+[Back to Index](#index)
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/CLI/manifests/mypod.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/CLI/manifests/mypod.yaml
new file mode 100644
index 00000000..64eaf05a
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/CLI/manifests/mypod.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: mypod
+spec:
+ containers:
+ - name: nginx
+ image: nginx:stable-alpine
+ ports:
+ - containerPort: 80
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/README.md b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/README.md
new file mode 100644
index 00000000..9e32e99d
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/README.md
@@ -0,0 +1,679 @@
+# Configuration
+
+Kubernetes has an integrated pattern for decoupling configuration from application or container.
+
+This pattern makes use of two Kubernetes components: ConfigMaps and Secrets.
+
+Both types of objects hold key-value pairs that can be injected into Pods through a variety of means.
+
+# Index
+
+* [ConfigMaps](#configmaps)
+ * [Exercise: Creating ConfigMaps](#exercise-creating-configmaps)
+ * [Exercise: Using ConfigMaps with Environment Variables](#exercise-using-configmaps-with-environment-variables)
+ * [Exercise: Using ConfigMaps with Volumes](#exercise-using-configmaps-with-volumes)
+* [Secrets](#secrets)
+ * [Exercise: Creating Secrets](#exercise-creating-secrets)
+ * [Exercise: Using Secrets with Environment Variables](#exercise-using-secrets-with-environment-variables)
+ * [Exercise: Using Secrets with Volumes](#exercise-using-secrets-with-volumes)
+* [Cleaning Up](#cleaning-up)
+* [Helpful Resources](#helpful-resources)
+
+
+----
+
+# ConfigMaps
+
+A ConfigMap is externalized data stored within Kubernetes that can be referenced through several different means:
+* Environment variable
+* A command line argument (via env var)
+* Injected as a file into a volume mount
+
+ConfigMaps can be created from a manifest, literals, a directory, or from the files the directly.
+
+---
+
+### Exercise: Creating ConfigMaps
+**Objective:** Go over the four methods of creating ConfigMaps.
+
+---
+
+#### **From Manifest**
+Create ConfigMap `manifest-example` from the manifest `manifests/cm-manifest.yaml` or use the yaml below.
+
+**manifests/cm-manifest.yaml**
+```yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: manifest-example
+data:
+ city: Ann Arbor
+ state: Michigan
+```
+
+**Command**
+```
+kubectl create -f manifests/cm-manifest.yaml
+```
+
+View the created ConfigMap.
+```
+kubectl get configmap manifest-example -o yaml
+```
+
+#### **From Literal**
+
+Create ConfigMap `literal-example` using the `--from-literal` flag and `city=Ann Arbor` along with `state=Michigan` for the values.
+```
+kubectl create cm literal-example --from-literal="city=Ann Arbor" --from-literal=state=Michigan
+```
+
+View the created ConfigMap.
+```
+kubectl get cm literal-example -o yaml
+```
+
+#### **From Directory**
+
+Create ConfigMap `dir-example` by using the `manifests/cm` directory as the source.
+```
+kubectl create cm dir-example --from-file=manifests/cm/
+```
+
+View the created ConfigMap.
+```
+kubectl get cm dir-example -o yaml
+```
+
+#### **From File**
+
+Create ConfigMap `file-example` by using the `city` and `state` files in the `manifests/cm` directory.
+```
+kubectl create cm file-example --from-file=manifests/cm/city --from-file=manifests/cm/state
+```
+
+View the created ConfigMap.
+```
+kubectl get cm file-example -o yaml
+```
+
+**Note:** When creating a ConfigMap from a file or directory the content will assume to be multiline as signified by the pipe symbol (`|`) in the yaml.
+
+---
+
+**Summary:**
+
+There are four primary methods of creating ConfigMaps with `kubectl`.
+
+From a manifest, passing literals on the command-line, supplying a path to a directory, or to the individual files themselves.
+
+These ConfigMaps are stored within etcd, and may be used in a multitude of ways.
+
+---
+
+### **Exercise: Using ConfigMaps with Environment Variables**
+
+**Objective:** Dive into how ConfigMap items may be referenced as Environment Variables and how this method may be extended to use them as command-line arguments.
+
+**Note:** This exercise builds off the previous exercise: [Creating ConfigMaps](#exercise-creating-configmaps). If you have not, complete it first before continuing.
+
+---
+
+1) Create Job `cm-env-example` using the manifest `manifests/cm-env-example.yaml` or the yaml below.
+
+**manifests/cm-env-example.yaml**
+```yaml
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: cm-env-example
+spec:
+ template:
+ spec:
+ containers:
+ - name: env
+ image: alpine:latest
+ command: ["/bin/sh", "-c"]
+ args: ["printenv CITY"]
+ env:
+ - name: CITY
+ valueFrom:
+ configMapKeyRef:
+ name: manifest-example
+ key: city
+ restartPolicy: Never
+```
+
+**Command:**
+```
+kubectl create -f manifests/cm-env-example.yaml
+```
+
+Note how the Environment Variable is injected using `valueFrom` and `configMapKeyRef`. This queries a specific key
+from the ConfigMap and injects it as an Environment Variable.
+
+2) List the Pods.
+```
+kubectl get pods
+```
+
+3) Copy the pod name and view the output of the Job.
+```
+kubectl logs cm-env-example-
+```
+
+It should echo the value from the `manifest-example` ConfigMap `city` key-value pair.
+
+This same technique can be used to inject the value for use in a Command.
+
+4) Create another Job `cm-cmd-example` from the manifest `manifests/cm-cmd-example.yaml` or use the yaml below.
+
+**manifests/cm-cmd-example.yaml**
+```yaml
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: cm-cmd-example
+spec:
+ template:
+ spec:
+ containers:
+ - name: env
+ image: alpine:latest
+ command: ["/bin/sh", "-c"]
+ args: ["echo Hello from ${CITY}!"]
+ env:
+ - name: CITY
+ valueFrom:
+ configMapKeyRef:
+ name: manifest-example
+ key: city
+ restartPolicy: Never
+```
+
+**Command:**
+```
+kubectl create -f manifests/cm-cmd-example.yaml
+```
+
+5) List the Pods.
+```
+kubectl get pods
+```
+
+3) Copy the pod name of the `cm-cmd-example` job and view the output of the Pod.
+```
+kubectl logs cm-cmd-example-
+```
+It should echo the string "Hello from " referencing the value from the `manifest-example` ConfigMap.
+
+---
+
+**Summary:**
+
+Items within a ConfigMap can be injected into a Pod's Environment Variables at container creation.
+
+These items may be picked up by the application being run in the container directly, or referenced as a command-line argument.
+
+Both methods are commonly used and enable a wide-variety of use-cases.
+
+---
+
+**Clean Up Command:**
+```
+kubectl delete job cm-env-example cm-cmd-example
+```
+
+---
+
+### **Exercise: Using ConfigMaps with Volumes**
+**Objective:** Learn how to mount a ConfigMap or specific items stored within a ConfigMap as a volume.
+
+**Note:** This exercise builds off the previous exercise: [Creating ConfigMaps](#exercise-creating-configmaps). If you
+have not, complete it first before continuing.
+
+---
+
+1) Create the Pod `cm-vol-example` using the manifest `manifests/cm-vol-example.yaml` or use the yaml below.
+
+**manifests/cm-vol-example.yaml**
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+ name: cm-vol-example
+spec:
+ containers:
+ - name: mypod
+ image: alpine:latest
+ command: ["/bin/sh", "-c"]
+ args:
+ - while true; do
+ sleep 10;
+ done
+ volumeMounts:
+ - name: config-volume
+ mountPath: /myconfig
+ - name: city
+ mountPath: /mycity
+ readOnly: true
+ volumes:
+ - name: config-volume
+ configMap:
+ name: manifest-example
+ - name: city
+ configMap:
+ name: manifest-example
+ items:
+ - key: city
+ path: thisismycity
+```
+
+**Command:**
+```
+kubectl create -f manifests/cm-vol-example.yaml
+```
+
+Note the volumes and how they are being referenced.
+
+The volume `city`, has an array of `items` that contains a sub-set of the key-value pairs stored in the `manifest-example` ConfigMap.
+
+When working with the individual items, it is possible to override the name or path to the generated file by supplying an argument for the `path` parameter.
+
+2) View the contents of the `/myconfig` volume mount.
+```
+kubectl exec cm-vol-example -- ls /myconfig
+```
+It will contain two files, matching the names of the keys stored in configMap `manifest-example`.
+
+3) `cat` the contents of the files.
+```
+kubectl exec cm-vol-example -- /bin/sh -c "cat /myconfig/*"
+```
+It will match the values stored in the configMap `manifest-example` concatenated together.
+
+4) View the contents of the other Volume Mount `mycity`.
+```
+kubectl exec cm-vol-example -- ls /mycity
+```
+A file will be present that represents the single item being referenced in the `city` volume. This file bears the
+name `thisismycity` as specified by the `path` variable.
+
+5) `cat` contents of the `thisismycity` file.
+```
+kubectl exec cm-vol-example -- cat /mycity/thisismycity
+```
+The contents should match the value of data[city].
+
+---
+
+**Summary:**
+
+In addition to being injected as Environment Variables it's possible to mount the contents of a ConfigMap as a volume.
+
+This same method may be augmented to mount specific items from a ConfigMap instead of the entire thing.
+
+These items can be renamed or be made read-only to meet a variety of application needs providing an easy to use avenue to further decouple application from configuration.
+
+---
+
+**Clean Up Command:**
+```
+kubectl delete pod cm-vol-example
+```
+
+```
+kubectl delete cm dir-example file-example literal-example manifest-example
+```
+
+---
+
+[Back to Index](#index)
+
+---
+---
+
+# Secrets
+
+A Secret is externalized "private" base64 encoded data stored within Kubernetes that can be referenced through several different means:
+* Environment variable
+* A command line argument (via env var)
+* Injected as a file into a volume mount
+
+Like ConfigMaps, Secrets can be created from a manifest, literals, or from files directly.
+
+**Note:** For all intents and purposes, Secrets are created and used just like ConfigMaps. If you have completed
+the ConfigMap Exercises, the Secrets section may be skimmed over glossing a few of the minor syntax differences.
+
+---
+
+### **Exercise: Creating Secrets**
+**Objective:** Learn to use the four different methods of creating Secrets, and how they different slightly from their ConfigMap counterparts.
+
+---
+
+#### **From Manifest**
+Create Secret `manifest-example` from the manifest `manifests/secret-manifest.yaml` or use the yaml below.
+
+**manifests/secret-manifest.yaml**
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: manifest-example
+type: Opaque
+data:
+ username: ZXhhbXBsZQ==
+ password: bXlwYXNzd29yZA==
+```
+
+**Command:**
+```
+kubectl create -f manifests/secret-manifest.yaml
+```
+
+Note the Secret has the additional attribute `type` when compared to a ConfigMap. The `Opaque` value simply means the data is unstructured. Additionally, the content referenced in `data` itself is base64 encoded. Decoded, they are `username=example` and `password=mypassword`.
+
+View the created Secret.
+```
+kubectl get secret manifest-example -o yaml
+```
+
+#### **From Literal**
+
+Create Secret `literal-example` using the `--from-literal` flag and `username=example` along with `password=mypassword` for the values.
+```
+kubectl create secret generic literal-example --from-literal=username=example --from-literal=password=mypassword
+```
+
+**Note:** Unlike ConfigMaps you **must** also specify the type of Secret you are creating. There are 3 types:
+* docker-registry - Credentials used to interact with a container registry.
+* generic - Eeuivalent to `Opaque`. Used for unstructured data.
+* tls - A TLS key pair (PEM Format) that accepts a cert (`--cert`) and key (`--key`).
+
+
+View the created Secret.
+```
+kubectl get secret literal-example -o yaml
+```
+
+#### **From Directory**
+
+Create Secret `dir-example` by using the `manifests/secret` directory as the source.
+```
+kubectl create secret generic dir-example --from-file=manifests/secret/
+```
+
+View the created Secret.
+```
+kubectl get secret dir-example -o yaml
+```
+
+#### **From File**
+
+Create ConfigMap `file-example` by using the `username` and `password` files in the `manifests/secret` directory.
+```
+kubectl create secret generic file-example --from-file=manifests/secret/username --from-file=manifests/secret/password
+```
+
+View the created Secret:
+```
+kubectl get secret file-example -o yaml
+```
+
+---
+
+**Summary:**
+
+Just like ConfigMaps, there are four primary methods of creating Secrets with `kubectl`. From manifests and literals to directories and files; no one method is better than another.
+
+The fundamental difference when working with Secrets over ConfigMaps, is that they require a type such as `generic` or `opaque` and the contents itself is stored in a base64 encoded form.
+
+---
+
+### **Exercise: Using Secrets with Environment Variables**
+**Objective:** Examine how Secrets may be referenced as Environment Variables and how this may be extended to use them in command-line arguments.
+
+**Note:** This exercise builds off the previous exercise: [Creating Secrets](#exercise-creating-Secrets). If you have not, complete it first before continuing.
+
+---
+
+1) Create Job `secret-env-example` using the manifest `manifests/secret-env-example.yaml` or the yaml below.
+
+**manifests/secret-env-example.yaml**
+```yaml
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: cm-env-example
+spec:
+ template:
+ spec:
+ containers:
+ - name: env
+ image: alpine:latest
+ command: ["/bin/sh", "-c"]
+ args: ["printenv USERNAME"]
+ env:
+ - name: USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: manifest-example
+ key: username
+ restartPolicy: Never
+```
+
+**Command:**
+```
+kubectl create -f manifests/secret-env-example.yaml
+```
+
+Note how the Environment Variable is injected using `valueFrom` and `secretKeyRef`.
+
+This queries a specific key from the Secret and injects it as an Environment Variable.
+
+2) List the Pods.
+```
+kubectl get pods
+```
+
+3) Copy the pod name and view the output of the Job.
+```
+kubectl logs secret-env-example-
+```
+It should echo the value from the `manifest-example` Secret `username` key-value pair.
+
+This same technique can be used to inject the value for use in a Command.
+
+4) Create another Job `secret-cmd-example` from the manifest `manifests/secret-cmd-example.yaml` or use the yaml below.
+
+**manifests/secret-cmd-example.yaml**
+```yaml
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: secret-cmd-example
+spec:
+ template:
+ spec:
+ containers:
+ - name: env
+ image: alpine:latest
+ command: ["/bin/sh", "-c"]
+ args: ["echo Hello there ${USERNAME}!"]
+ env:
+ - name: USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: manifest-example
+ key: username
+ restartPolicy: Never
+```
+
+**Command**
+```
+kubectl create -f manifests/secret-cmd-example.yaml
+```
+
+5) List the Pods.
+```
+kubectl get pods
+```
+
+3) Copy the pod name of the `secret-cmd-example` job and view the output of the Pod.
+```
+kubectl logs secret-cmd-example-
+```
+It should echo the string "Hello there !" referencing the value from the `manifest-example` Secret.
+
+---
+
+**Summary:**
+
+Secrets may be injected into a Pod's Environment Variables at container creation.
+
+These variables may be picked up by the application being run in the container directly, or referenced as a command-line argument.
+
+Both methods are useful in a wide-variety of scenarios enabling further decoupling of application and configuration.
+
+---
+
+**Clean Up Command:**
+```
+kubectl delete job secret-env-example secret-cmd-example
+```
+
+---
+
+### **Exercise: Using Secrets with Volumes**
+**Objective:** Learn how to mount a Secret or specific items stored within a Secret as a volume.
+
+**Note:** This exercise builds off the previous exercise: [Creating Secrets](#exercise-creating-secrets). If you have not, complete it first before continuing.
+
+---
+
+1) Create the Pod `secret-vol-example` using the manifest `manifests/secret-vol-example.yaml` or use the yaml below.
+
+**manifests/secret-vol-example.yaml**
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+ name: secret-vol-example
+spec:
+ containers:
+ - name: mypod
+ image: alpine:latest
+ command: ["/bin/sh", "-c"]
+ args:
+ - while true; do
+ sleep 10;
+ done
+ volumeMounts:
+ - name: secret-volume
+ mountPath: /mysecret
+ - name: password
+ mountPath: /mypass
+ readOnly: true
+ volumes:
+ - name: secret-volume
+ secret:
+ secretName: manifest-example
+ - name: password
+ secret:
+ secretName: manifest-example
+ items:
+ - key: password
+ path: supersecretpass
+```
+
+**Command:**
+```
+kubectl create -f manifests/secret-vol-example.yaml
+```
+
+Note the volumes and how they are being referenced. The volume `password`, has an array of `items` that contains a sub-set of the key-value pairs stored in the `manifest-example` Secret.
+
+When working with the individual items, it is possible to override the name or path to the generated file by supplying an argument for the `path` parameter.
+
+2) View the contents of the `/mysecret` volume mount.
+```
+kubectl exec secret-vol-example -- ls /mysecret
+```
+It will contain two files, matching the names of the keys stored in Secret `manifest-example`.
+
+3) `cat` the contents of the files.
+```
+kubectl exec secret-vol-example -- /bin/sh -c "cat /mysecret/*"
+```
+It will match the values stored in the Secret `manifest-example` concatenated together.
+
+4) View the contents of the other Volume Mount `mypass`.
+```
+kubectl exec secret-vol-example -- ls /mypass
+```
+A file will be present that represents the single item being referenced in the `password` volume. This file bears the
+name `supersecretpass` as specified by the `path` variable.
+
+5) `cat` contents of the `supersecretpass` file.
+```
+kubectl exec secret-vol-example -- cat /mypass/supersecretpass
+```
+The contents should match the value of data[password].
+
+---
+
+**Summary:** Secrets can be consumed in multiple ways. One of the more flexible (and secure) methods being mounting as a volume.
+
+It's possible to mount the entire contents of a Secret as a volume, or alternatively mount specific
+items stored in a Secret.
+
+These items can be renamed or be made read-only to meet a variety of application needs.
+
+---
+
+**Clean Up Command:**
+```
+kubectl delete pod secret-vol-example
+```
+
+```
+kubectl delete secret dir-example file-example literal-example manifest-example
+```
+
+---
+
+[Back to Index](#index)
+
+---
+---
+
+# **Cleaning Up**
+
+```
+kubectl delete cm manifest-example literal-example dir-example file-example
+```
+
+```
+kubectl delete secret manifest-example literal-example dir-example file-example
+```
+
+---
+
+[Back to Index](#index)
+
+---
+---
+
+# Helpful Resources
+
+* [Configure a Pod to Use a ConfigMap](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/)
+* [Secrets Overview](https://kubernetes.io/docs/concepts/configuration/secret/)
+* [Storing and Using Docker Registry Credentials as a Secret](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/)
+* [ConfigMaps and Secrets](https://github.com/AbstractInfrastructure/k8s-intro-tutorials/tree/master/configuration)
+
+
+---
+
+[Back to Index](#index)
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm-cmd-example.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm-cmd-example.yaml
new file mode 100644
index 00000000..aa20da9d
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm-cmd-example.yaml
@@ -0,0 +1,19 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: cm-cmd-example
+spec:
+ template:
+ spec:
+ containers:
+ - name: env
+ image: alpine:latest
+ command: ["/bin/sh", "-c"]
+ args: ["echo Hello from ${CITY}!"]
+ env:
+ - name: CITY
+ valueFrom:
+ configMapKeyRef:
+ name: manifest-example
+ key: city
+ restartPolicy: Never
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm-env-example.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm-env-example.yaml
new file mode 100644
index 00000000..6d73254a
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm-env-example.yaml
@@ -0,0 +1,19 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: cm-env-example
+spec:
+ template:
+ spec:
+ containers:
+ - name: env
+ image: alpine:latest
+ command: ["/bin/sh", "-c"]
+ args: ["printenv CITY"]
+ env:
+ - name: CITY
+ valueFrom:
+ configMapKeyRef:
+ name: manifest-example
+ key: city
+ restartPolicy: Never
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm-manifest.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm-manifest.yaml
new file mode 100644
index 00000000..5c88056f
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm-manifest.yaml
@@ -0,0 +1,7 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: manifest-example
+data:
+ city: Ann Arbor
+ state: Michigan
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm-vol-example.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm-vol-example.yaml
new file mode 100644
index 00000000..3ef3f8cb
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm-vol-example.yaml
@@ -0,0 +1,29 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: cm-vol-example
+spec:
+ containers:
+ - name: mypod
+ image: alpine:latest
+ command: ["/bin/sh", "-c"]
+ args:
+ - while true; do
+ sleep 10;
+ done
+ volumeMounts:
+ - name: config-volume
+ mountPath: /myconfig
+ - name: city
+ mountPath: /mycity
+ readOnly: true
+ volumes:
+ - name: config-volume
+ configMap:
+ name: manifest-example
+ - name: city
+ configMap:
+ name: manifest-example
+ items:
+ - key: city
+ path: thisismycity
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm/city b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm/city
new file mode 100644
index 00000000..e9b38c2a
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm/city
@@ -0,0 +1 @@
+Ann Arbor
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm/state b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm/state
new file mode 100644
index 00000000..d051ebad
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/cm/state
@@ -0,0 +1 @@
+Michigan
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret-cmd-example.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret-cmd-example.yaml
new file mode 100644
index 00000000..2615dd8e
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret-cmd-example.yaml
@@ -0,0 +1,19 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: secret-cmd-example
+spec:
+ template:
+ spec:
+ containers:
+ - name: env
+ image: alpine:latest
+ command: ["/bin/sh", "-c"]
+ args: ["echo Hello there ${USERNAME}!"]
+ env:
+ - name: USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: manifest-example
+ key: username
+ restartPolicy: Never
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret-env-example.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret-env-example.yaml
new file mode 100644
index 00000000..085bf86f
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret-env-example.yaml
@@ -0,0 +1,19 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: secret-env-example
+spec:
+ template:
+ spec:
+ containers:
+ - name: mypod
+ image: alpine:latest
+ command: ["/bin/sh", "-c"]
+ args: ["printenv USERNAME"]
+ env:
+ - name: USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: manifest-example
+ key: username
+ restartPolicy: Never
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret-manifest.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret-manifest.yaml
new file mode 100644
index 00000000..f549c138
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret-manifest.yaml
@@ -0,0 +1,8 @@
+apiVersion: v1
+kind: Secret
+metadata:
+ name: manifest-example
+type: Opaque
+data:
+ username: ZXhhbXBsZQ==
+ password: bXlwYXNzd29yZA==
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret-vol-example.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret-vol-example.yaml
new file mode 100644
index 00000000..2a7f6d90
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret-vol-example.yaml
@@ -0,0 +1,29 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: secret-vol-example
+spec:
+ containers:
+ - name: mypod
+ image: alpine:latest
+ command: ["/bin/sh", "-c"]
+ args:
+ - while true; do
+ sleep 10;
+ done
+ volumeMounts:
+ - name: secret-volume
+ mountPath: /mysecret
+ - name: password
+ mountPath: /mypass
+ readOnly: true
+ volumes:
+ - name: secret-volume
+ secret:
+ secretName: manifest-example
+ - name: password
+ secret:
+ secretName: manifest-example
+ items:
+ - key: password
+ path: supersecretpass
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret/password b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret/password
new file mode 100644
index 00000000..48d23cfd
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret/password
@@ -0,0 +1 @@
+mypassword
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret/username b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret/username
new file mode 100644
index 00000000..33a9488b
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/manifests/secret/username
@@ -0,0 +1 @@
+example
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/README.md b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/README.md
new file mode 100644
index 00000000..e759a5ff
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/README.md
@@ -0,0 +1,20 @@
+# **Kubernetes Tutorials**
+
+## **Before you begin**
+
+These tutorials make use of [kind][kind]. A tool that allows users to quickly spin up and run a single instance of Kubernetes locally using Docker.
+
+To install it and the other tutorial dependencies, see the [Installation Guides](#installation-guides) section.
+
+Each section assumes an instance of kind is up and running. To start kind for the first time, use the command:
+
+```
+kind create cluster
+```
+
+---
+
+## **Tutorial Index**
+* [CLI](/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/CLI/README.md) - Covers the basics of using `kubectl` to interact with a Kubernetes cluster.
+* [storage](/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/README.md) - Explores the relationship between Persistent Volumes, Persistent Volume Claims, and Volumes themselves.
+* [ConfigMaps and Secrets](/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/Configuration/README.md) - Tutorials going over how to use the two Configuration objects ConfigMaps and Secrets.
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/README.md b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/README.md
new file mode 100644
index 00000000..816885f4
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/README.md
@@ -0,0 +1,619 @@
+# Index
+- [Index](#index)
+- [Storage](#storage)
+- [Volumes](#volumes)
+ - [Exercise: Using Volumes with Pods](#exercise-using-volumes-with-pods)
+- [Persistent Volumes and Claims](#persistent-volumes-and-claims)
+ - [Exercise: Understanding Persistent Volumes and Claims](#exercise-understanding-persistent-volumes-and-claims)
+ - [Exercise: Using PersistentVolumeClaims](#exercise-using-persistentvolumeclaims)
+- [Storage Classes](#storage-classes)
+ - [Exercise: Exploring StorageClasses](#exercise-exploring-storageclasses)
+- [Helpful Resources](#helpful-resources)
+
+# Storage
+
+Pods by themselves are useful, but many workloads require exchanging data between containers, or persisting some
+form of data.
+
+For this task we have Volumes, Persistent Volumes, Persistent Volume Claims, and Storage Classes.
+
+---
+
+# Volumes
+Volumes within Kubernetes are storage that is tied to the Pod’s lifecycle.
+
+A pod can have one or more type of volumes attached to it.
+These volumes are consumable by any of the containers within the pod.
+
+They can survive Pod restarts; however their durability beyond that is dependent on the Volume Type.
+
+---
+
+### Exercise: Using Volumes with Pods
+**Objective:** Understand how to add and reference volumes to a Pod and their containers.
+
+---
+
+1) Create a Pod with from the manifest `manifests/volume-example.yaml` or the yaml below.
+
+**manifests/volume-example.yaml**
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+ name: volume-example
+spec:
+ containers:
+ - name: nginx
+ image: nginx:stable-alpine
+ ports:
+ - containerPort: 80
+ volumeMounts:
+ - name: html
+ mountPath: /usr/share/nginx/html
+ readOnly: true
+ - name: content
+ image: alpine:latest
+ volumeMounts:
+ - name: html
+ mountPath: /html
+ command: ["/bin/sh", "-c"]
+ args:
+ - while true; do
+ echo $(date) >> /html/index.html;
+ sleep 5;
+ done
+ volumes:
+ - name: html
+ emptyDir: {}
+```
+
+**Command**
+```
+kubectl create -f manifests/volume-example.yaml
+```
+
+Note the relationship between `volumes` in the Pod spec, and the `volumeMounts` directive in each container.
+
+2) Exec into `content` container within the `volume-example` Pod, and `cat` the `html/index.html` file.
+```
+kubectl exec volume-example -c content -- /bin/sh -c "cat /html/index.html"
+```
+You should see a list of date time-stamps. This is generated by the script being used as the entrypoint (`args`) of the
+content container.
+
+3) Now do the same within the `nginx` container, using `cat` to see the content of `/usr/share/nginx/html/index.html`
+example.
+```
+kubectl exec volume-example -c nginx -- /bin/sh -c "cat /usr/share/nginx/html/index.html"
+```
+You should see the same file.
+
+4) Now try to append "nginx" to `index.html` from the `nginx` container.
+```
+kubectl exec volume-example -c nginx -- /bin/sh -c "echo nginx >> /usr/share/nginx/html/index.html"
+```
+It should error out and complain about the file being read only. The `nginx` container has no reason to write to the
+file, and mounts the same Volume as read-only. Writing to the file is handled by the `content` container.
+
+---
+
+**Summary:** Pods may have multiple volumes using different Volume types. Those volumes in turn can be mounted to one
+or more containers within the Pod by adding them to the `volumeMounts` list. This is done by referencing their name and
+supplying their `mountPath`. Additionally, volumes may be mounted both read-write or read-only depending on the
+application, enabling a variety of use-cases.
+
+---
+
+**Clean Up Command**
+```
+kubectl delete pod volume-example
+```
+
+---
+
+[Back to Index](#index)
+
+---
+---
+
+# Persistent Volumes and Claims
+
+Persistent Volumes and Claims work in conjunction to serve as the direct method in which a Pod Consumes Persistent
+storage.
+
+A `PersistentVolume` (PV) is a representation of a cluster-wide storage resource that is linked to a backing storage
+provider - `NFS`, `GCEPersistentDisk`, `RBD` etc.
+
+A `PersistentVolumeClaim` acts as a namespaced _request_ for storage that satisfies a set of a requirements instead
+of mapping to the storage resource directly.
+
+This separation of PV and PVC ensures that an application’s _‘claim’_ for storage is portable across numerous backends
+or providers.
+
+---
+
+### Exercise: Understanding Persistent Volumes and Claims
+**Objective:** Gain an understanding of the relationship between Persistent Volumes, Persistent Volume Claims, and
+the multiple ways they may be selected.
+
+---
+
+1) Create PV `pv-sc-example` from the manifest `manifests/pv-sc-example.yaml` or use the yaml below. Ensure to note
+that its labeled with `type=hostpath`, its Storage Class Name is set to `mypvsc`, and uses `Delete` for the Reclaim
+Policy.
+
+**manifests/pv-sc-example.yaml**
+```yaml
+kind: PersistentVolume
+apiVersion: v1
+metadata:
+ name: pv-sc-example
+ labels:
+ type: hostpath
+spec:
+ capacity:
+ storage: 2Gi
+ accessModes:
+ - ReadWriteMany
+ persistentVolumeReclaimPolicy: Delete
+ storageClassName: mypvsc
+ hostPath:
+ type: DirectoryOrCreate
+ path: "/data/mypvsc"
+```
+
+**Command**
+```
+kubectl create -f manifests/pv-sc-example.yaml
+```
+
+2) Once created, list the available Persistent Volumes.
+```
+kubectl get pv
+```
+You should see the single PV `pv-sc-example` flagged with the status `Available`. Meaning no claim has been issued
+that targets it.
+
+3) Create PVC `pvc-selector-example` from the manifest `manifests/pvc-selector-example.yaml` or the yaml below.
+
+**manifests/pvc-selector-example.yaml**
+```yaml
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: pvc-selector-example
+spec:
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 1Gi
+ selector:
+ matchLabels:
+ type: hostpath
+```
+
+**Command**
+```
+kubectl create -f manifests/pvc-selector-example.yaml
+```
+
+Note that the selector targets `type=hostpath`.
+
+4) Then describe the newly created PVC
+```
+kubectl describe pvc pvc-selector-example
+```
+The pvc `pvc-selector-example` should be in a `Pending` state with the Error Event `FailedBinding` and
+`no Persistent Volumes available for this claim and no storage class is set`. If a PV is given a `storageClassName`,
+**ONLY** PVCs that request that Storage Class may use it, even if the selector has a valid target.
+
+5) Now create the PV `pv-selector-example` from the manifest `manifests/pv-selector-example.yaml` or the yaml below.
+
+**manifests/pv-selector-example.yaml**
+```yaml
+kind: PersistentVolume
+apiVersion: v1
+metadata:
+ name: pv-selector-example
+ labels:
+ type: hostpath
+spec:
+ capacity:
+ storage: 2Gi
+ accessModes:
+ - ReadWriteMany
+ hostPath:
+ type: DirectoryOrCreate
+ path: "/data/mypvselector"
+```
+
+**Command**
+```
+kubectl create -f manifests/pv-selector-example.yaml
+```
+
+6) Give it a few moments and then look at the Persistent Volumes once again.
+```
+kubectl get pv
+```
+The PV `pv-selector-example` should now be in a `Bound` state, meaning that a PVC has been mapped or _"bound"_ to it.
+Once bound, **NO** other PVCs may make a claim against the PV.
+
+7) Create the pvc `pvc-sc-example` from the manifest `manifests/pvc-sc-example.yaml` or use the yaml below.
+
+**manifests/pvc-sc-example.yaml**
+```yaml
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: pvc-sc-example
+spec:
+ accessModes:
+ - ReadWriteMany
+ storageClassName: mypvsc
+ resources:
+ requests:
+ storage: 1Gi
+```
+
+**Command**
+```
+kubectl create -f manifests/pvc-sc-example.yaml
+```
+
+Note that this PVC has a `storageClassName` reference and no selector.
+
+8) Give it a few seconds and then view the current PVCs.
+```
+kubectl get pvc
+```
+The `pvc-sc-example` should be bound to the `pv-sc-example` Volume. It consumed the PV with the corresponding
+`storageClassName`.
+
+9) Delete both PVCs.
+```
+kubectl delete pvc pvc-sc-example pvc-selector-example
+```
+
+10) Then list the PVs once again.
+```
+kubectl get pv
+```
+The `pv-sc-example` will not be listed. This is because it was created with a `persistentVolumeReclaimPolicy`
+of `Delete` meaning that as soon as the PVC was deleted, the PV itself was deleted.
+
+PV `pv-selector-example`, was created without specifying a `persistentVolumeReclaimPolicy` and was in turn created
+with the default for PVs: `Retain`. It's state of `Released` means that it's associated PVC has been deleted.
+In this state no other PVC's may claim it, even if `pvc-selector-example` was created again. The PV must **manually**
+be reclaimed or deleted. This ensures the preservation of the state of the Volume in the event that its PVC was
+accidentally deleted giving an administrator time to do something with the data before reclaiming it.
+
+11) Delete the PV `pv-selector-example`.
+```
+kubectl delete pv pv-selector-example
+```
+
+---
+
+**Summary:** Persistent Volumes and Persistent Volume Claims when bound together provide the primary method of
+attaching durable storage to Pods. Claims may reference PVs by specifying a `storageClassName`, targeting them
+with a selector, or a combination of both. Once a PV is bound to a PVC, it becomes a tightly coupled relationship and
+no further PVCs may issue a claim against the PV, even if the binding PVC is deleted. How PVs are reclaimed is
+configured via the PV attribute `persistentVolumeReclaimPolicy` where they can either be deleted automatically when
+set to `Delete` or require manual intervention when set to `Retain` as a data-preservation safe-guard.
+
+---
+
+### Exercise: Using PersistentVolumeClaims
+**Objective:** Learn how to consume a Persistent Volume Claim within a Pod, and explore some of the ways they may
+be used.
+
+---
+
+1) Create PV and associated PVC `html` using the manifest `manifests/html-vol.yaml`
+
+**manifest/html-vol.yaml**
+```yaml
+kind: PersistentVolume
+apiVersion: v1
+metadata:
+ name: html
+ labels:
+ type: hostpath
+spec:
+ capacity:
+ storage: 1Gi
+ accessModes:
+ - ReadWriteMany
+ storageClassName: html
+ persistentVolumeReclaimPolicy: Delete
+ hostPath:
+ type: DirectoryOrCreate
+ path: "/tmp/html"
+
+---
+
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: html
+spec:
+ accessModes:
+ - ReadWriteMany
+ storageClassName: html
+ resources:
+ requests:
+ storage: 1Gi
+```
+
+**Command**
+```
+kubectl create -f manifests/html-vol.yaml
+```
+
+2) Create Deployment `writer` from the manifest `manifests/writer.yaml` or use the yaml below. It is similar to the
+[`volume-example` Pod from the first exercise](#exercise-using-volumes-with-pods), but now uses a
+`persistentVolumeClaim` Volume instead of an `emptyDir`.
+
+**manifests/writer.yaml**
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: writer
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: writer
+ template:
+ metadata:
+ labels:
+ app: writer
+ spec:
+ containers:
+ - name: content
+ image: alpine:latest
+ volumeMounts:
+ - name: html
+ mountPath: /html
+ command: ["/bin/sh", "-c"]
+ args:
+ - while true; do
+ date >> /html/index.html;
+ sleep 5;
+ done
+ volumes:
+ - name: html
+ persistentVolumeClaim:
+ claimName: html
+```
+
+**Command**
+```
+kubectl create -f manifests/writer.yaml
+```
+
+Note that the `claimName` references the previously created PVC defined in the `html-vol` manifest.
+
+2) Create a Deployment and Service `reader` from the manifest `manifests/reader.yaml` or use the yaml below.
+
+**manifests/reader.yaml**
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reader
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: reader
+ template:
+ metadata:
+ labels:
+ app: reader
+ spec:
+ containers:
+ - name: nginx
+ image: nginx:stable-alpine
+ ports:
+ - containerPort: 80
+ volumeMounts:
+ - name: html
+ mountPath: /usr/share/nginx/html
+ readOnly: true
+ volumes:
+ - name: html
+ persistentVolumeClaim:
+ claimName: html
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: reader
+spec:
+ selector:
+ app: reader
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 80
+```
+
+**Command**
+```
+kubectl create -f manifests/reader.yaml
+```
+
+
+3) With the `reader` Deployment and Service created, use `kubectl proxy` to view the `reader` Service.
+```
+kubectl proxy
+```
+**URL**
+```
+http://127.0.0.1:8001/api/v1/namespaces/default/services/reader/proxy/
+```
+The `reader` Pods can reference the same Claim as the `writer` Pod. This is possible because the PV and PVC were
+created with the access mode `ReadWriteMany`.
+
+4) Now try to append "nginx" to `index.html` from one of the `reader` Pods.
+```
+kubectl exec reader-- -- /bin/sh -c "echo nginx >> /usr/share/nginx/html/index.html"
+```
+The `reader` Pods have mounted the Volume as read only. Just as it did with exercise 1, The command should error out
+with a message complaining about not being able to modify a read-only filesystem.
+
+---
+
+**Summary:** Using Persistent Volume Claims with Pods is quite easy. The attribute `persistentVolumeClaim.claimName`
+simply must reference the name of the desired PVC in the Pod's Volume definition. Multiple Pods may reference the same
+PVC as long as their access mode supports it.
+
+---
+
+**Clean Up Command**
+```
+kubectl delete -f manifests/reader.yaml -f manifests/writer.yaml -f manifests/html-vol.yaml
+```
+
+---
+
+[Back to Index](#index)
+
+---
+---
+
+# Storage Classes
+
+Storage classes are an abstraction on top of an external storage resource (PV). They work directly with the external
+storage system to enable dynamic provisioning and remove the need for the cluster admin to pre-provision Persistent
+Volumes.
+
+---
+
+### Exercise: Exploring StorageClasses
+**Objective:** Understand how it's possible for a Persistent Volume Claim to consume dynamically provisioned storage
+via a Storage Class.
+
+---
+
+1) Re-enable the kind default-storageclass, and wait for it to become available
+```
+kubectl annotate --overwrite sc standard storageclass.kubernetes.io/is-default-class="true"
+```
+
+2) Describe the new Storage Class
+```
+kubectl describe sc standard
+```
+Note the fields `IsDefaultClass`, `Provisioner`, and `ReclaimPolicy`. The `Provisioner` attribute references the
+_"driver"_ for the Storage Class. Kind comes with it's own driver `rancher.io/local-path` that simply mounts
+a hostpath from within the VM as a Volume.
+
+3) Create PVC `pvc-standard` from the manifest `manifests/pvc-standard.yaml` or use the yaml below.
+
+**manifests/pvc-standard.yaml**
+```yaml
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: pvc-standard
+spec:
+ accessModes:
+ - ReadWriteMany
+ storageClassName: standard
+ resources:
+ requests:
+ storage: 1Gi
+```
+
+**Command**
+```
+kubectl create -f manifests/pvc-standard.yaml
+```
+
+4) Describe the PVC `pvc-standard`
+```
+kubectl describe pvc pvc-standard
+```
+The `Events` lists the actions that occurred when the PVC was created. The external provisioner `standard` provisions
+a Volume for the claim `default/pvc-standard` and is assigned the name `pvc-`.
+
+5) List the PVs.
+```
+kubectl get pv
+```
+The PV `pvc-` will be the **exact** size of the associated PVC.
+
+6) Now create the PVC `pvc-selector-example` from the manifest `manifests/pvc-selector-example.yaml` or use the yaml
+below.
+
+**manifests/pvc-selector-example.yaml**
+```yaml
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: pvc-selector-example
+spec:
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 1Gi
+ selector:
+ matchLabels:
+ type: hostpath
+```
+
+**Command**
+```
+kubectl create -f manifests/pvc-selector-example.yaml
+```
+
+7) List the PVCs.
+```
+kubectl get pvc
+```
+The PVC `pvc-selector-example` was bound to a PV automatically, even without a valid selector target. The `standard`
+Storage Class was configured as the default, meaning that **any** PVCs that do not have a valid target will default to
+using the `standard` Storage Class.
+
+8) Delete both PVCs.
+```
+kubectl delete pvc pvc-standard pvc-selector-example
+```
+
+9) List the PVs once again.
+```
+kubectl get pv
+```
+The PVs were automatically reclaimed following the `ReclaimPolicy` that was set by the Storage Class.
+
+---
+
+**Summary:** Storage Classes provide a method of dynamically provisioning Persistent Volumes from an external Storage
+System. They have the same attributes as normal PVs, and have their own methods of being garbage collected. They may
+be targeted by name using the `storageClassName` within a Persistent Volume Claim request, or a Storage Class may be
+configured as default ensuring that Claims may be fulfilled even when there is no valid selector target.
+
+---
+
+[Back to Index](#index)
+
+---
+---
+
+# Helpful Resources
+
+* [Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/)
+* [Storage Classes](https://kubernetes.io/docs/concepts/storage/storage-classes/)
+
+---
+
+[Back to Index](#index)
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/html-vol.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/html-vol.yaml
new file mode 100644
index 00000000..785fbc70
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/html-vol.yaml
@@ -0,0 +1,30 @@
+kind: PersistentVolume
+apiVersion: v1
+metadata:
+ name: html
+ labels:
+ type: hostpath
+spec:
+ capacity:
+ storage: 1Gi
+ accessModes:
+ - ReadWriteMany
+ storageClassName: html
+ persistentVolumeReclaimPolicy: Delete
+ hostPath:
+ type: DirectoryOrCreate
+ path: "/tmp/html"
+
+---
+
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: html
+spec:
+ accessModes:
+ - ReadWriteMany
+ storageClassName: html
+ resources:
+ requests:
+ storage: 1Gi
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pv-sc-example.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pv-sc-example.yaml
new file mode 100644
index 00000000..df29011e
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pv-sc-example.yaml
@@ -0,0 +1,16 @@
+kind: PersistentVolume
+apiVersion: v1
+metadata:
+ name: pv-sc-example
+ labels:
+ type: hostpath
+spec:
+ capacity:
+ storage: 2Gi
+ accessModes:
+ - ReadWriteMany
+ storageClassName: mypvsc
+ persistentVolumeReclaimPolicy: Delete
+ hostPath:
+ type: DirectoryOrCreate
+ path: "/tmp/mypvsc"
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pv-selector-example.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pv-selector-example.yaml
new file mode 100644
index 00000000..c84f5809
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pv-selector-example.yaml
@@ -0,0 +1,15 @@
+kind: PersistentVolume
+apiVersion: v1
+metadata:
+ name: pv-selector-example
+ labels:
+ type: hostpath
+spec:
+ capacity:
+ storage: 2Gi
+ accessModes:
+ - ReadWriteMany
+ persistentVolumeReclaimPolicy: Retain
+ hostPath:
+ type: DirectoryOrCreate
+ path: "/tmp/mypvselector"
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pvc-sc-example.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pvc-sc-example.yaml
new file mode 100644
index 00000000..ce312dde
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pvc-sc-example.yaml
@@ -0,0 +1,11 @@
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: pvc-sc-example
+spec:
+ accessModes:
+ - ReadWriteMany
+ storageClassName: mypvsc
+ resources:
+ requests:
+ storage: 1Gi
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pvc-selector-example.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pvc-selector-example.yaml
new file mode 100644
index 00000000..1c7c5cf1
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pvc-selector-example.yaml
@@ -0,0 +1,13 @@
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: pvc-selector-example
+spec:
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 1Gi
+ selector:
+ matchLabels:
+ type: hostpath
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pvc-standard.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pvc-standard.yaml
new file mode 100644
index 00000000..6ef50bdd
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/pvc-standard.yaml
@@ -0,0 +1,11 @@
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: pvc-standard
+spec:
+ accessModes:
+ - ReadWriteMany
+ storageClassName: standard
+ resources:
+ requests:
+ storage: 1Gi
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/reader.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/reader.yaml
new file mode 100644
index 00000000..1c91533f
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/reader.yaml
@@ -0,0 +1,41 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reader
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: reader
+ template:
+ metadata:
+ labels:
+ app: reader
+ spec:
+ containers:
+ - name: nginx
+ image: nginx:stable-alpine
+ ports:
+ - containerPort: 80
+ volumeMounts:
+ - name: html
+ mountPath: /usr/share/nginx/html
+ readOnly: true
+ volumes:
+ - name: html
+ persistentVolumeClaim:
+ claimName: html
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: reader
+spec:
+ selector:
+ app: reader
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 80
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/volume-example.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/volume-example.yaml
new file mode 100644
index 00000000..399493ef
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/volume-example.yaml
@@ -0,0 +1,29 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: volume-example
+spec:
+ containers:
+ - name: nginx
+ image: nginx:stable-alpine
+ ports:
+ - containerPort: 80
+ volumeMounts:
+ - name: html
+ mountPath: /usr/share/nginx/html
+ readOnly: true
+ - name: content
+ image: alpine:latest
+ volumeMounts:
+ - name: html
+ mountPath: /html
+ command: ["/bin/sh", "-c"]
+ args:
+ - while true; do
+ echo $(date) >> /html/index.html;
+ sleep 5;
+ done
+ volumes:
+ - name: html
+ emptyDir: {}
+
diff --git a/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/writer.yaml b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/writer.yaml
new file mode 100644
index 00000000..a9174b25
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/k8s-intro-tutorials/storage/manifests/writer.yaml
@@ -0,0 +1,30 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: writer
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: writer
+ template:
+ metadata:
+ labels:
+ app: writer
+ spec:
+ containers:
+ - name: content
+ image: alpine:latest
+ volumeMounts:
+ - name: html
+ mountPath: /html
+ command: ["/bin/sh", "-c"]
+ args:
+ - while true; do
+ date >> /html/index.html;
+ sleep 5;
+ done
+ volumes:
+ - name: html
+ persistentVolumeClaim:
+ claimName: html
diff --git a/Kubernetes-Basic-2-Days/Modules/labels.yml b/Kubernetes-Basic-2-Days/Modules/labels.yml
new file mode 100644
index 00000000..7c9d94df
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/labels.yml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: label-demo
+ labels:
+ environment: production
+ app: nginx
+spec:
+ containers:
+ - name: nginx
+ image: nginx:1.14.2
+ ports:
+ - containerPort: 80
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/pod.yaml b/Kubernetes-Basic-2-Days/Modules/pod.yaml
new file mode 100644
index 00000000..4ee0ad49
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/pod.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: nginx
+spec:
+ containers:
+ - name: nginx
+ image: nginx:1.14.2
+ ports:
+ - containerPort: 80
\ No newline at end of file
diff --git a/Kubernetes-Basic-2-Days/Modules/replicaset.yaml b/Kubernetes-Basic-2-Days/Modules/replicaset.yaml
new file mode 100644
index 00000000..f0f3ac9c
--- /dev/null
+++ b/Kubernetes-Basic-2-Days/Modules/replicaset.yaml
@@ -0,0 +1,20 @@
+apiVersion: apps/v1
+kind: ReplicaSet
+metadata:
+ name: frontend
+ labels:
+ app: guestbook
+ tier: frontend
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ tier: frontend
+ template:
+ metadata:
+ labels:
+ tier: frontend
+ spec:
+ containers:
+ - name: php-redis
+ image: gcr.io/google_samples/gb-frontend:v3
\ No newline at end of file
diff --git a/Kubernetes-CheatSheet_LinuxAcademy.pdf b/Kubernetes-CheatSheet_LinuxAcademy.pdf
new file mode 100644
index 00000000..74b731a1
Binary files /dev/null and b/Kubernetes-CheatSheet_LinuxAcademy.pdf differ
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..6c3c52e4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,847 @@
+# Practical Kubernetes Exercices
+
+This repo provides some resources to learn Kubernetes through practical exercises for self study to learn how easy it is to understand and master Kubernetes complexity and problems.
+
+Kubernetes is easy to understand, even if it looks hard at the first look on the icons or the resources map, this course is about to help you to understand K8s and learn how to start!
+
+![icons-all](images/icons-all.png "icons-all")
+
+![k8s-resources-map](images/k8s-resources-map.png "k8s-resources-map")
+
+
+## Prerequisites
+
+It would be nice if you know what `kubectl` is and have a basic understanding of running conatiners with docker / containerd or cri-o.
+
+## Preparation
+
+To get prepared please install at least kubectx and kns with krew from this list and make sure to have bash completion for kubectl in place:
+
+## Tools we use
+
+- [mkcert](https://github.com/FiloSottile/mkcert)
+- watch
+ - Mac setup:
+ ````
+ brew install watch
+- [oh-my-zsh](https://github.com/ohmyzsh/ohmyzsh)
+ - activate autocompletion
+ - [mac setup](https://docs.brew.sh/Shell-Completion)
+ - [kubectl plugin](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/kubectl)
+- [git](https://git-scm.com/)
+- [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
+ - mac setup:
+ ```
+ brew install kubernetes-cli
+- [kubectx & kubens](https://github.com/ahmetb/kubectx)
+
+
+[The Golden Kubernetes Tooling and Helpers list](http://bit.ly/kubernetes-tooling-list)
+
+We can use any Kubernetes cluster (> 1.21) on our local machine or in the cloud. For online trainings we recommend to have either k3s installed with k3d, use Kind, or Docker for Desktop.
+
+We'll use some slides from:
+
+[Kubernauts Kubernetes Trainings Slides](https://goo.gl/Hzk2sd)
+
+and refer to some resources from:
+
+[Kubernauts Kubernetes Learning Resources List](https://goo.gl/Rywkpd)
+
+## Kubernetes Guides
+
+### Networking
+
+The purpose of [this website](https://www.tkng.io/) is to provide an overview of various Kubernetes networking components with a specific focus on exactly how they implement the required functionality.
+
+The guide is split into multiple parts which can be studied mostly independently, however they all work together to provide a complete end-to-end cluster network abstractions.
+
+Where possible, every topic in this guide will include a dedicated [hands-on labs](https://www.tkng.io/lab/) which can be spun up locally in a matter of minutes.
+
+### Security
+
+The Security checklist aims at providing a basic list of guidance with links to more comprehensive documentation on each topic. It does not claim to be exhaustive and is meant to evolve.
+
+1- https://kubernetes.io/docs/concepts/security/security-checklist/
+
+2- https://github.com/magnologan/awesome-k8s-security
+
+3- https://github.com/freach/kubernetes-security-best-practice
+
+4- https://medium.com/@seifeddinerajhi/kubernetes-security-assessment-guidelines-and-necessary-checklist-9a326f341b68
+
+5- https://medium.com/@seifeddinerajhi/owasp-kubernetes-top-10-a-comprehensive-guide-f03af6fd66ed
+
+### Storage
+
+The key concepts of Kubernetes storage, including PVs, PVCs, and StorageClass.
+
+- https://medium.com/@seifeddinerajhi/understanding-storage-in-kubernetes-ee2c19001aae
+
+### Misc
+
+Kelsey Hightower's open-source guide, [Kubernetes the Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way), goes through how to bootstrap a Kubernetes cluster without the use of installers or scripts.
+
+
+Learnk8s(https://learnk8s.io/): Develop the knowledge and skills to get the most out of Kubernetes with hands-on online courses and instructor-led classes.
+
+
+
+### Useful aliases
+
+Expand here to see the solution
+
+
+```yaml
+alias k="kubectl"
+alias kx="kubectx"
+alias kn="kubens"
+alias kgp="kubectl get pods"
+alias kgel="k get events --sort-by=.metadata.creationTimestamp"
+```
+
+
+
+
+## Kubectl CheatSheet and Goodies
+
+https://kubernetes.io/docs/reference/kubectl/cheatsheet/
+
+https://github.com/dennyzhang/cheatsheet-kubernetes-A4
+
+Expand here to see the solution
+
+
+```bash
+k get events --sort-by=.metadata.creationTimestamp # List Events sorted by timestamp
+
+k get services --sort-by=.metadata.name # List Services Sorted by Name
+
+k get pods --sort-by=.metadata.name
+
+k get endpoints
+
+k explain pods,svc
+
+k get pods -A # --all-namespaces
+
+k get nodes -o jsonpath='{.items[*].spec.podCIDR}'
+
+k get pods -o wide
+
+k get pod my-pod -o yaml --export > my-pod.yaml # Get a pod's YAML without cluster specific information
+
+k get pods --show-labels # Show labels for all pods (or other objects)
+
+k get pods --sort-by='.status.containerStatuses[0].restartCount'
+
+k cluster-info
+
+k api-resources
+
+k api-resources -o wide
+
+kubectl api-resources --verbs=list,get # All resources that support the "list" and "get" request verbs
+
+k get apiservice
+```
+
+
+
+### k create namespace imperative via declarative
+
+Expand here to see the solution
+
+
+```yaml
+k create ns
+k create ns --dry-run test -o yaml > test-ns.yaml
+k create -f test-ns.yaml
+k delete ns test
+```
+
+
+
+
+### k create / run pods or deploymens with dry-run
+
+
+ Expand here to see the solution
+
+
+```yaml
+# old school (going to get deprecated)
+k run --generator=run-pod/v1 --image= --dry-run -o yaml >
+
+k run --generator=run-pod/v1 "nginx-pod" --image=nginx -o yaml --dry-run > nginx-pod.yaml
+
+or
+
+k run --restart=Never --image= --dry-run -o yaml >
+
+or (new school with --dry-run=client)
+
+k run nginx-pod --image=nginx -o yaml --dry-run=client > nginx-pod.yaml
+
+k create --dry-run -o yaml >
+
+k create deployment nginx-deployment --image=nginx --dry-run -o yaml > nginx-deployment.yaml
+
+cat nginx-pod.yaml
+
+cat nginx-deployment.yaml
+
+k create -f nginx-pod.yaml
+
+# create a service via exposing the pod
+
+k expose pod nginx-pod --port=80
+
+k get svc
+
+k port-forward service/nginx-pod 8080:80
+
+or
+
+k proxy
+
+open http://127.0.0.1:8001/api/v1/namespaces/default/pods/nginx-pod/proxy/
+
+# open a new terminal session
+
+curl http://127.0.0.1:8080/
+
+k delete all --all # with caution!!!
+
+k create -f nginx-deployment.yaml
+
+k get all
+
+k get all -A
+
+k expose deployment nginx-deployment --port=80
+
+k port-forward service/nginx-deployment 8080:80
+
+k scale --replicas 3 deployment nginx-deployment
+
+k edit deployment nginx-deployment
+
+vi nginx-deployment.yaml # adapt the number of replicas, e.g. to 2
+
+k apply -f nginx-deployment.yaml
+
+```
+
+
+
+### k get events and logs, describe objects
+
+Expand here to see the solution
+
+
+```yaml
+kx
+kn
+k delete all --all # with caution!!!
+k apply -f 0-nginx-all.yaml
+k get all
+# where is the ingress?
+k get ingress # ingress objects are not namespaced
+k get events
+k get events -A
+k get events -n
+k logs nginx-
+k describe pod nginx-
+k describe deployment nginx
+k describe replicasets nginx-
+```
+
+
+
+### Merging contexts (e.g. merge 2 kubeconfigs from 2 cluster contexts)
+
+Sometimes you'll need to merge multiple kubeconfigs into a single file, here you go:
+
+Expand here to see the solution
+
+
+```bash
+KUBECONFIG=file1:file2:file3 kubectl config view --merge --flatten > my_new_kubeconfig
+or
+cp ~/.kube/config ~/.kube/config.bak
+KUBECONFIG=/my/new/kubeconfig:~/.kube/config.bak kubectl config view --flatten > my_new_kubeconfig
+# test it
+export KUBECONFIG=my_new_kubeconfig
+kx
+cp my_new_kubeconfig ~/.kube/config
+```
+
+
+
+Don't miss: Mastering the KUBECONFIG file by Ahmet Alp Balkan:
+
+https://ahmet.im/blog/mastering-kubeconfig/
+
+### Kubernetes Secrets are not secret
+
+Secrets are resources containing keys with base64 encoded values. Secrets are not encrypted by default, they are only encoded and can get decoded easily by everyone who has access to a namespace or to the whole cluster.
+
+Secret values can be exposed to pods as environment variables or mounted as files.
+
+In order to create a secret from a text file, you can run the following, This creates a generic secret named secretname and automatically encodes the value as base64:
+
+Expand here to see the solution
+
+
+```yaml
+echo -n "yourvalue" > ./secret.txt
+k create secret generic secretname --from-file=./secret.txt
+k describe secrets secretname
+k get secret secretname -o yaml
+echo 'eW91cnZhbHVl' | base64 --decode
+# or
+k create secret generic mysecret --dry-run -o yaml --from-file=./secret.txt > secret.yaml
+k create -f secret.yaml
+# or
+k create secret generic mysecret --dry-run -o yaml --from-literal=secret.txt=yourvalue > secret.yaml
+```
+
+
+
+#### Further reading:
+
+Since K8s secrets are not so secret, there are some ways to keep you secrets secret:
+
+https://learnk8s.io/kubernetes-secrets-in-git
+
+https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/#create-a-pod-that-has-access-to-the-secret-data-through-environment-variables
+
+
+
+### Kubernetes ConfigMaps
+
+A ConfigMap is an object consisting of key-value pairs which can be injected into your application.
+
+With a ConfigMap you can separate configuration from your Pods. This way, you can prevent hardcoding configuration data.
+
+ConfigMaps are useful for storing and sharing non-sensitive, unencrypted configuration information. Sensitive information should be stored in a Secret instead.
+
+Exercise:
+
+Create a ConfigMap named kubernauts that contains a key named dev with the value ops.
+
+With the --from-literal argument passed to the k create configmap command you can create a ConfigMap containing a text value.
+
+Expand here to see the solution
+
+
+```yaml
+k create cm kubernauts --from-literal=dev=ops --dry-run -o yaml > cm-kubernauts.yaml
+cat cm-kubernauts.yaml
+echo -n "ops" > dev
+k create cm kubernauts --from-file=./dev
+k get cm
+k describe cm kubernauts
+k delete cm kubernauts
+k create -f cm-kubernauts.yaml
+k describe cm kubernauts
+```
+
+
+
+Using this ConfigMap, we can inject data in our application:
+
+Expand here to see the solution
+
+
+```yaml
+cat 0-nginx-configmap.yaml
+k create -f 0-nginx-configmap.yaml
+```
+
+
+
+
+
+## Whoami, Whoareyou and Whereami Problems
+
+### What We’ll Do
+
+We’ll use a pre-made container — containous/whoami — capable of telling you where it is hosted and what it receives when you call it.
+
+If you'd like to build the container image with docker, do:
+
+Expand here to see the solution
+
+
+```yaml
+git clone https://github.com/containous/whoami.git
+docker build -t whoami .
+docker tag whoami kubernautslabs/whoami
+docker push kubernautslabs/whoami
+docker images | head
+```
+
+
+
+
+We’ll define two different deployments, a whoami and a whoareyou deployment that will use `containous/whoami` container image.
+
+We’ll create a deployment to ask Kubernetes to deploy 2 replicas of whoami and 3 replicas of whoareyou.
+
+We’ll define two services, one for each of our Pods.
+
+We’ll define Ingress objects to define the routes to our services to the outside world.
+
+We’ll use our Nginx Ingress Controller on our Rancher Cluster.
+
+Explanations about the file content of whoami-deployment.yaml:
+
+We define a “deployment” (kind: Deployment)
+
+The name of the object is “whoami-deployment” (name: whoami-deployment)
+
+We want two replica (replicas: 2)
+
+It will deploy pods that have the label app:whoami (selector: matchLabels: app:whoami)
+
+Then we define the pods with the (template: …) which will have the whoami label (metadata:labels:app:whoami)
+
+The Pods will host a container using the image containous/whoami (image:containous/whoami)
+
+Expand here to see the solution
+
+
+```yaml
+k apply -f 1-whoami-deployment.yaml
+k get all
+# we expose the deployment with a service of type ClusterIP
+k create -f 1-whoami-service-ClusterIP.yaml
+k get svc
+k port-forward service/whoami-service 8080:80
+# in a new terminal session call
+curl 127.0.0.1:8080
+k delete svc whoami-service
+# create a service of type NodePort
+k create -f 1-whoami-service-nodeport.yaml
+k get svc
+curl csky08:30056 # adapt the nodeport for your env. please !
+curl csky09:30056
+curl csky10:30056
+k delete svc whoami-service-nodeport
+k create -f 1-whoami-service-loadbalancer.yaml
+k get svc
+curl # the external-ip is given from the LB IP pool above
+k create -f 2-whoareyou-all.yml
+k get all
+k get svc
+k get ing
+curl
+# are you happy? ;-)
+```
+
+
+
+
+## DNS based Service discovery with whereami kubia pod
+
+### What We’ll Do
+
+We'll use a slightly extended node.js app (which is a simple web server) from the [Kubernetes in Action book by Marko Lukša](https://www.amazon.com/-/en/Marko-Luksa/dp/1617293725) in 2 different namespaces ns1 and ns2 to demonstrate the DNS based services discovery.
+
+A service provides a Virtual IP (VIP) address, which means the Service IP is not bound to a physical network interface. A service acts like an internal loadbalancer in K8s! The magic of of routing trafic through the VIP is implemented by IPtable rules managed by kube-proxy!
+
+A service can be called through its FQDN in the form of:
+
+`$SERVICE_NAME.$NAMESPACE.svc.cluster.local`
+
+Expand here to see the solution
+
+
+```yaml
+cd whereami
+k create ns ns1
+k create ns ns2
+kn ns1
+cat kubia-deployment.yaml
+k create -f kubia-deployment.yaml
+k create -f kubia-deployment.yaml -n ns2
+k expose deployment kubia
+k get svc
+k expose deployment kubia -n ns2
+k get svc -n ns2
+k exec -it kubia- -- curl kubia.ns2.svc.cluster.local:8080
+k scale deployment kubia -n ns2 --replicas 3
+# repeat the service call many times and see how loadbalancing works
+k exec -it kubia- -- curl kubia.ns2.svc.cluster.local:8080
+k exec -n ns2 -it kubia- -- curl kubia.ns1.svc.cluster.local:8080
+k exec -it kubia- -- ping kubia.ns2.svc.cluster.local
+--> PING kubia.ns2.svc.cluster.local (10.43.109.89) 56(84) bytes of data.
+# you don't get any pong, why?
+# ssh into a node and examine the IPtable rules
+sudo iptables-save | grep kubia
+```
+
+
+
+### Headless Services for Stickiness
+
+![hadless](images/headless-cluster-ip.png "headless-cluster-ip")
+
+As we learned services are exposed by default through the type ClusterIP, they work as an internal layer 4 load-balancer and provide a VIP with a stable DNS address, where the clients can connect to. The service forwards the connections to one of the pods which are backing the service via round robin.
+
+This works fine and is desired for stateless apps which need to connect to one of the pods randomly and gain more performance through trafic routing via load balancing.
+
+But in some cases where stickiness is needed and the clients need to connect to a particular pod for session or data stickiness, then we need to define our service without ClusterIP, which is by default the head of the service (that's the VIP).
+
+To do that we need to define our service as a `headless` service, let's see that in action with the whereami service and our utils pod.
+
+In the following we expose the kubia deployment as a headless service by setting the ClusterIP to `None`, scale the deployment and do a DNS query to both services with `host kubia-headless` and `host kubia-clusterip` from within the util client pod. As you'll see our client pod always connects to the first IP from the DNS response, if we curl the headless service. This means no load balancing happens, the call is `Sticky`!
+
+The second curl to the service with ClusterIP does load balancing and distributes the traffic between pods.
+
+Expand here to see the solution
+
+
+```yaml
+k delete svc kubia
+k expose deployment kubia --name kubia-headless --cluster-ip None
+k expose deployment kubia --name kubia-clusterip
+k expose deployment kubia --name kubia-lb --type=LoadBalancer
+k scale deployment kubia --replicas 3
+k run --generator=run-pod/v1 utils -it --image kubernautslabs/utils -- bash
+# inside the utils container
+host kubia-headless
+host kubia-clusterip
+# what is the difference here?
+for i in $(seq 1 10) ; do curl kubia-headless:8080; done
+# hits kubia only on one node?
+for i in $(seq 1 10) ; do curl kubia-clusterip:8080; done
+# does load balancing via the head ;-)
+exit
+mkcert '*.whereami.svc'
+k create secret tls whereami-secret --cert=_wildcard.whereami.svc.pem --key=_wildcard.whereami.svc-key.pem
+cat kubia-ingress-tls.yaml
+k create -f kubia-ingress-tls.yaml
+# Please provide the host entry mapping in your /etc/hosts file like this:
+# 192.168.64.23 my.whereami.svc
+# the IP should be the IP of the traefik loadbalancer / ingress controller
+curl https://my.whereami.svc
+for i in $(seq 1 10) ; do curl https://my.whereami.svc; done
+# the ingress controller does load balancing, although the kubia-headless is defined as the backend with serviceName: kubia-headless!
+```
+
+
+
+
+## Ingress with TLS
+
+![ingress-controller](images/ingress-controller-traefik.png "ingress-controller-traefik")
+
+Often we need to use an ingress object to provide path based or (sub-) domain based routing with TLS termination and other capabilities defined through annotations in the ingress resource.
+
+By creating an ingress for a service, the ingress controller will create a single entry-point to the defined service in the ingress resource on every node in the cluster.
+
+In the follwoing we're using the traefik ingress controller and an ingress object to provide path based or (sub-) domain based routing with TLS termination with a valid mkcert made TLS certificate on our lab environment.
+
+
+Expand here to see the solution
+
+
+```yaml
+cd ..
+kn default
+mkcert '*.ghost.svc'
+k create secret tls ghost-secret --cert=_wildcard.ghost.svc.pem --key=_wildcard.ghost.svc-key.pem
+# alternatively, if you can't or you don't want to use mkcert, you can create a selfsigned cert with:
+# openssl genrsa -out tls.key 2048
+# openssl req -new -x509 -key tls.key -out tls.cert -days 360 -subj /CN=my.ghost.svc
+# k create secret tls ghost-secret --cert=tls.cert --key=tls.key
+cat 3-ghost-deployment.yaml
+k create -f 3-ghost-deployment.yaml
+k expose deployment ghost --port=2368
+cat 3-ghost-ingress-tls.yaml
+k create -f 3-ghost-ingress-tls.yaml
+# Please provide the host entry mapping in your /etc/hosts file like this:
+# 192.168.64.23 my.ghost.svc admin.ghost.svc
+# the IP should be the IP of the traefik loadbalancer / ingress controller
+open https://my.ghost.svc
+open https://admin.ghost.svc/ghost
+# change the service type to LoadBalancer and access ghost with the loadbalancer IP on port 2368 or on any other node (works on k3s with trafik only), e.g.:
+open http://node2:2368
+# scale the deployment to have 2 replicas and see how the backend ghost backened https://admin.ghost.svc/ghost doesn't work.
+```
+
+
+
+
+## Multi-Container Pods
+
+Create a Pod with two containers, both with image alpine and command "echo hello; sleep 3600". Connect to the second container and run 'ls'.
+
+The easiest way to do it is to create a pod with a single container and save its definition in a YAML file and extend it with an additional container:
+
+Expand here to see the solution
+
+
+```yaml
+k run alpine-2-containers --image=alpine --restart=Never -o yaml --dry-run -- /bin/sh -c 'echo hello;sleep 3600' > alpine-pod.yaml
+```
+
+Copy/paste the container related values, so your final YAML should contain the following two containers (make sure those containers have a different name):
+
+```YAML
+containers:
+ - args:
+ - /bin/sh
+ - -c
+ - echo hello;sleep 3600
+ image: alpine
+ name: alpine1
+ resources: {}
+ - args:
+ - /bin/sh
+ - -c
+ - echo hello;sleep 3600
+ image: alpine
+ name: alpine2
+ resources: {}
+```
+
+```yaml
+k create -f alpine-pod-2-containers.yaml # alpine-pod-2-containers.yaml is in this repo
+# exec / ssh into to the alpine2 container
+k exec -it alpine-2-containers -c alpine2 -- sh
+ls
+exit
+
+# or just an one-liner
+k exec -it alpine2 -c alpine2 -- ls
+
+# cleanup
+k delete pod alpine-2-containers
+```
+
+
+
+
+
+### Shared Volume
+
+We'll extend the above alpine-2-containers with a shared volume of type emptyDir named `share` with a volumeMount for each container with a mountPath `/tmp/share1` and `/tmp/share2` as follow:
+
+Expand here to see the solution
+
+
+```yaml
+cat alpine-pod-share-volumes.yaml
+k apply -f alpine-pod-share-volumes.yaml
+k exec -it alpine-2-containers-share-volume -c alpine1 -- sh
+touch /tmp/share1/sharefile
+echo "test-share1" > /tmp/share1/sharefile
+cat /tmp/share1/sharefile
+exit
+k exec -it alpine-2-containers-share-volume -c alpine2 -- cat /tmp/share2/sharefile
+```
+
+
+
+
+## Security
+
+Kubernetes Security is a huge topic and security hardening is a nice problem which everyone has to implement according to their security requirements and the governance model of their organization. We're going only to scratch the surface of K8s security here and highly recommend to go through the following resources by Michael Hausenblas, Liz Rice and the community.
+
+https://kubernetes-security.info/
+
+https://learn.hashicorp.com/vault/getting-started-k8s/sidecar
+
+https://github.com/k8s-sec/k8s-sec.github.io
+
+
+### Service Accounts
+
+In K8s each namespace has a default ServiceAccount, named `default`. A ServiceAccount is a namespaced resource used by containers running in a Pod, to communicate with the API server of the Kubernetes cluster. ServiceAccounts with limited permissions are often used to apply the principle of least priviledge.
+
+```bash
+k get sa --all-namespaces | grep default
+k get sa default -o yaml
+k get secret default- -o yaml
+```
+
+The data key of this Secret has several key/pairs:
+
+```yaml
+apiVersion: v1
+kind: Secret
+data:
+ ca.crt: LS0tLS1CRUdJTi...
+ namespace: ZGVmYXVsdA==
+ token: ZXlKaGJHY2lP...
+metadata:
+ annotations:
+ kubernetes.io/service-account.name: default
+...
+```
+
+The token is the Base64 encoding of the JWT used to authenticate against the API server.
+Let's get the token and head to jwt.io and use the debugger to decode the token.
+
+```bash
+kubectl run -it alpine --restart=Never --image=alpine -- sh
+ls /var/run/secrets/kubernetes.io/serviceaccount/
+cat /var/run/secrets/kubernetes.io/serviceaccount/token
+exit
+open https://jwt.io/
+```
+
+Paste the token and get the payload, which looks similar to this:
+
+```
+{
+ "iss": "kubernetes/serviceaccount",
+ "kubernetes.io/serviceaccount/namespace": "default",
+ "kubernetes.io/serviceaccount/secret.name": "default-token-24pbl",
+ "kubernetes.io/serviceaccount/service-account.name": "default",
+ "kubernetes.io/serviceaccount/service-account.uid": "147e134a-43d0-4c76-ad01-bccc59f8acb9",
+ "sub": "system:serviceaccount:default:default"
+}
+```
+
+We can see the service account default is linked to the namespace where it exists and is using the secret default-token-24pbl. This token is available in the filesystem of each container of the Pod of the attached ServiceAccount.
+
+### Using a Custom ServiceAccount
+
+A Service Account on its own is on not so useful, we need to provide rome rights and permissions to it through a set of rules defined through roles or cluster roles using the RBAC implementation in K8s.
+
+
+### RBAC (Role Based Access Control)
+
+RBAC in K8s is activated by default and helps to provide access to resources (objects) like namespaces, pods, services, etc. to those Subjects or Entities like users, group or service accounts who need access to some resources and deny access to other resources who do not need access to them. RBAC increases security in K8s projects and shall be defined through a governance model in each organization (but in the theorie, you know we are all admins ;-)).
+
+RBAC is implemented through Role, ClusterRole, RoleBinding, and ClusterRoleBinding.
+
+#### Role
+
+A Role defines what you or a subject can do to a set of resources, like get, set, delete, etc.A Role contains a set of rules which define a set of permissions. Roles are used to assigning permissions to resources on the namespace level.
+
+#### ClusterRole
+
+Similar to Role, ClusterRole can grant permissions on the Cluster Level such as giving resource permissions across all namespaces in the cluster.
+
+#### RoleBinding and ClusterRoleBinding
+
+RoleBinding and ClusterRoleBinding are used to grant permissions and priviledges to Subjects or Entities on the namespace (project RoleBinding) level or on the cluster level (ClusterRoleBinding).
+
+![RBAC](images/rbac.png "rbac")
+
+#### What We’ll Do
+
+We create a new namespace myapp and a new custom ServiceAccount `mysa`, create a new role `podreader` with the permission to get and list pods and create a rolebinding `mypodviewer` to bind the ServiceAccount to the role podreader in the namespace `myapp`.
+
+Expand here to see the solution
+
+
+```yaml
+k get clusterroles | wc -l
+# 62
+k get clusterroles
+k describe clusterrole view
+k describe clusterrole view | grep pods
+# the view role allows your application access to many other resources such as deployments and services.
+k create namespace myapp
+k -n=myapp create serviceaccount mysa
+k -n myapp create role podreader --verb=get --verb=list --resource=pods
+k -n myapp describe role/podreader
+# nice, the role podreader can only view now, but we need to attach the role podreader to our application, represented by the service account myapp.
+k -n myapp create rolebinding mypodviewer --role=podreader --serviceaccount=myapp:mysa
+k -n myapp describe rolebindings mypodviewer
+k -n myapp auth can-i --as=system:serviceaccount:myapp:mysa list pods
+# yes :-)
+k -n myapp auth can-i --as=system:serviceaccount:myapp:mysa list services
+# no :-)
+```
+
+
+
+We extend our alpine pod with the key `serviceAccountName` and the value `mysa`, apply the change and run a shell in the alpine-pod, get the toke belonging to the `mysa` ServiceAccountand use it to list the pods in the default namespace and the myapp namespace to see the differences:
+
+Expand here to see the solution
+
+
+```yaml
+
+kn myapp
+cat alpine-pod-service-account.yaml
+k apply -f alpine-pod-service-account.yaml
+k describe pod alpine-sa
+k get sa
+k get secrets
+k exec -it alpine-sa -- sh
+apk add curl
+TOKEN=$(cat /run/secrets/kubernetes.io/serviceaccount/token)
+curl -H "Authorization: Bearer $TOKEN" https://node1:6443/api/v1/namespaces/default/pods/ --insecure
+curl -H "Authorization: Bearer $TOKEN" https://node1:6443/api/v1/namespaces/myapp/pods/ --insecure
+# what works, what doesn't work?
+
+```
+
+
+
+#### Further reading:
+
+[Kubernetes Tips: Using a ServiceAccount](https://medium.com/better-programming/k8s-tips-using-a-serviceaccount-801c433d0023)
+
+#### Permission Manager
+
+--> ToDo
+
+## 3-Tier App (MVC)
+
+Please read the README and the related blog post in the [subfolder](3-tier-app/README.md) 3-tier-app and try to understand and get the todo list app up and running.
+
+# Day 2 Operation
+
+Day 2 operation is mainly about implementing some principles like selfhealing and autoscaling for our apps AND the infrastructure components like nodes and K8s components itself and define resources limits, liveness and readiness probes for our apps, run continious security auditing, apply GitOps principles and style, etc.
+
+In this first section we'll go through app auto scaling with Horizontal Pod Autoscaler.
+
+![hpa](images/pod-autoscaling-hpa.png "hap")
+
+## Pod AutoScaling with HPA (Horizontal Pod Autoscaler)
+
+```bash
+kubectl run hpa-example --image=k8s.gcr.io/hpa-example --requests=cpu=200m --expose --port=80
+# create HPA based on CPU usage
+kubectl autoscale deployment hpa-example --cpu-percent=50 --min=1 --max=10
+# In another terminal run
+kubectl run -i --tty generate-load --image=busybox /bin/sh
+# Inside the above container run a loop bash command to stress the CPU
+while true; do wget -q -O- http://hpa-example.default.svc.cluster.local; done
+# Check HPA Status
+kubectl get hpa
+```
+
+## GitOps
+
+GitOps is an operating model for Kubernetes and other cloud native technologies. It provides a set of best practices that unifies deployment, management, and monitoring for clusters and applications. Another way to put it is: a path towards a developer experience for managing applications; where end-to-end CI and CD pipelines and Git workflows
+
+- https://www.eksworkshop.com/docs/automation/gitops/
+
+- https://medium.com/@seifeddinerajhi/gitops-ci-cd-automation-workflow-using-github-actions-argocd-and-helm-charts-deployed-on-k8s-3811b253030b
+
+
+
+### Coming next
+
+* Cluster Operation and maintanance
+
+* Nodes AutoScaling and AutoSpotting (on AWS)
+
+* Logging and Monitoring with Operators
+
+* TroubleShooting
+
+* Cloud Native Storage for Statefulsets
+
+* Backup & Recovery
\ No newline at end of file
diff --git a/_wildcard.ghost.svc-key.pem b/_wildcard.ghost.svc-key.pem
new file mode 100644
index 00000000..b09c6390
--- /dev/null
+++ b/_wildcard.ghost.svc-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDC4lP4W2gDwSh+
+lovrfbdFHtq0v1gsm1dbypmT0i++kYl30i07M0bi4tpylOhpUtukC//yb02eYXL0
+ZzQplL6qwUlQiXl7WjKtbuWiY5iDrRjiKmv2JmKLPIFn8aLgJ7C+sYbr3dQA0ZDq
+pxMBMct+wg4GBL52e0HbRktJ0SL6MmKq4ICyOpE5823lUl6YjmaV7+/57gLqqAAi
+usRGlqakj0kGXOwdXiyH5H4fbAVk2+KBwE0iIj/kRcWa63NuoO1h6mBhmUZkJlez
+eYuVnGXi4nL6JN+rqGLQi/BvytbsGuXT/T5I+2G2Y7jYMl43dDRmQmrPg7jArkBx
+EEdmakjBAgMBAAECggEAYEinye2HL0uwcRJ6IKfk8y5ySZi7vJYnC//F7sWKtzF6
+ZIufsz77R79iw/eT9+1q/Nq84o9hHt3wiJWwrNaDeSOz0CmLroj6vrsqkxd3056i
+y6K/4kZGq5oCKVO1799MMHrPORtI0fq4CWbwOcfbTU4c1ZZkb28oM2jAa8D68fcz
+8A6oKMbiL0BlXT3Emn9hT5DDcZLsBook61zzLaYnYlbsjKO5gVBHjI6EY6OOfFf1
+rpwaJTaOhqz15CuAD1brdyo2mEuUuNy26gk4lh2OevkvbjHaqewyBgzMiofkqGLi
+gk8q9Yuvu+UiYk9xYDxJhGxuYn1bdUkLKAyRlGlkXQKBgQDn+9cABSf0lhV498PD
+sXJIMJcJV/CC5J6ROipqrtrEtKLndV0wx5OuyHLv5Qcqh6k+64Zx+DZ7jUSkSGI1
+tapZxjIU9XrKQXFU4gmH77YmSDA8tYB52LNsTfYSXBMFINwAYfVpXLZBMhTcx74J
+hwPtCPk4kwOVTEOozpDbSUQqmwKBgQDXD0C4DHx+f//KhWfRVgEq31+Y90f5Jzv7
+nSl10lNH+w2WtV+6yg5B+BmbDQ0qHkF2llSa8iDODApWKt/sswylEJomSkE3p7RT
+LimKOji5Dr2L6CS4FWUnkzS7spO7v7CxfcAYX9UJTpvtuTua7IeSpqpNvDrU7n6X
+h/9v5rKx0wKBgA/mhxoNQGvXTal48gYbx4WDLxcI3AdcvDGgFwAw8/W/m9rZhIWv
+aEP2oUooHJGhsswJQLHXHYTibe4EuBaOWRrGJvCg0sXCLo5u39BdcdK15/iBSEkR
+vVqTDWa8wOD9G5c7H6MVI7jcQenQFwp4IqDAmLRz/y7gh1KutecR4oY5AoGAUO9U
+k+9fCtxxD26VW5raZaAbAh5N3958HH1RFR5KaVR6ELXBiTJxmzIbsNaAldE9IbwB
+qy5kWib93N/V1easY5KT8MURNjjPDF7bE0JGBp8dhoGfEAg9QV+NAPZ70rSZcrK4
+kHPAYPhMhnKnk+5gNzix7v9fxLLcwXpVD2/q4DECgYEA0U6KZOP99nYuFtkChMOl
+YByuRVnt+jpM32m8u3YPEV9t6kJ1Z34SxM2PJiQwMjcGBb4BZxwPVLDyvC8GIWsX
+0NthhAmd9c6xppQ8Z6GbdQdNPKfDaxwZlDQdgaRTlMzwRIrmUVmL3M1eC7ZZeKEJ
+JI8Wa+GEdCK75c3pRxroJxs=
+-----END PRIVATE KEY-----
diff --git a/_wildcard.ghost.svc.pem b/_wildcard.ghost.svc.pem
new file mode 100644
index 00000000..979e3674
--- /dev/null
+++ b/_wildcard.ghost.svc.pem
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEdDCCAtygAwIBAgIQPrqhAAghd3KAfBDpVuicYTANBgkqhkiG9w0BAQsFADCB
+mTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMTcwNQYDVQQLDC5hcmFz
+aEBBcmFzaHMtTUJQLmZyaXR6LmJveCAoQXJhc2ggS2FmZmFtYW5lc2gpMT4wPAYD
+VQQDDDVta2NlcnQgYXJhc2hAQXJhc2hzLU1CUC5mcml0ei5ib3ggKEFyYXNoIEth
+ZmZhbWFuZXNoKTAeFw0xOTA2MDEwMDAwMDBaFw0zMDEwMjUxMTIyMTRaMGIxJzAl
+BgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0ZTE3MDUGA1UECwwu
+YXJhc2hAQXJhc2hzLU1CUC5mcml0ei5ib3ggKEFyYXNoIEthZmZhbWFuZXNoKTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMLiU/hbaAPBKH6Wi+t9t0Ue
+2rS/WCybV1vKmZPSL76RiXfSLTszRuLi2nKU6GlS26QL//JvTZ5hcvRnNCmUvqrB
+SVCJeXtaMq1u5aJjmIOtGOIqa/YmYos8gWfxouAnsL6xhuvd1ADRkOqnEwExy37C
+DgYEvnZ7QdtGS0nRIvoyYqrggLI6kTnzbeVSXpiOZpXv7/nuAuqoACK6xEaWpqSP
+SQZc7B1eLIfkfh9sBWTb4oHATSIiP+RFxZrrc26g7WHqYGGZRmQmV7N5i5WcZeLi
+cvok36uoYtCL8G/K1uwa5dP9Pkj7YbZjuNgyXjd0NGZCas+DuMCuQHEQR2ZqSMEC
+AwEAAaNuMGwwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwG
+A1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU/6zEE9LnbW18OrhIo6jWU9m+VZ8wFgYD
+VR0RBA8wDYILKi5naG9zdC5zdmMwDQYJKoZIhvcNAQELBQADggGBAHHhcMaLWhKK
+jHvDgLBaQu7fiR4dfiqLWOeLLGe965GXQmGlSO99FNCadmIk6iHWd8x3NPYBbAia
+2oT+2gM51FflcKMIJHh0Elbq4AE5CLyRnnpQXDfLqfHkHwHGaSXGMKaqMtZxCedm
+6iaV0Q6ySDROpVjiI6/kXenBqK/3sHUAqDe9I1hhelY/if71W9V2pQaszQCTDVNa
+N1TK6hQ02R+3UeTfQ/h8jar1P5+8Q6zOOdwaMYRcrcy4Q5QrjxlAwBiaUgYZz61N
+e4P4mKgUpnj0KT5SQ8VeSAuL2LI7ElrA2Qzqd5Sa+o7tXgPZrgCp0zSwJuNiktk6
+UoALfj6AC1i6XItn3iUgizY/CZ/P7IryymzkSaGFwyfwePTnPzvaUZiOSGwbtMkV
+1NujJgocVqUdZTGVm4hK/KUAtJ4ULLE5jrSbjes2eAq1pI3UZP0xx6r+I+pCEZCt
+aLf9g3Ffdc3BwVCLHVEHENtjEo7beNrUWCXO9F5iOpwSc+lOrAdODA==
+-----END CERTIFICATE-----
diff --git a/addons/prometheus-operator/delete_crds b/addons/prometheus-operator/delete_crds
new file mode 100644
index 00000000..126b3617
--- /dev/null
+++ b/addons/prometheus-operator/delete_crds
@@ -0,0 +1,6 @@
+kubectl delete crd alertmanagers.monitoring.coreos.com
+kubectl delete crd podmonitors.monitoring.coreos.com
+kubectl delete crd prometheuses.monitoring.coreos.com
+kubectl delete crd prometheusrules.monitoring.coreos.com
+kubectl delete crd servicemonitors.monitoring.coreos.com
+kubectl delete crd thanosrulers.monitoring.coreos.com
diff --git a/addons/prometheus-operator/graf-ingress.yaml b/addons/prometheus-operator/graf-ingress.yaml
new file mode 100644
index 00000000..dd194023
--- /dev/null
+++ b/addons/prometheus-operator/graf-ingress.yaml
@@ -0,0 +1,25 @@
+#apiVersion: extensions/v1beta1 #changed
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: graf-ingress
+ namespace: monitoring
+ annotations:
+ kubernetes.io/ingress.class: "traefik"
+ labels:
+ app: prometheus
+spec:
+ rules:
+ - host: graf.kubernauts.local
+ http:
+ paths:
+ - path: /
+ pathType: Prefix #changed
+ backend:
+ #serviceName: promo-grafana #changed
+ service:
+ name: promo-grafana
+ #servicePort: 80 #changed
+ port:
+ number: 80
+
diff --git a/addons/prometheus-operator/promo-ingress.yaml b/addons/prometheus-operator/promo-ingress.yaml
new file mode 100644
index 00000000..8d3ba1b0
--- /dev/null
+++ b/addons/prometheus-operator/promo-ingress.yaml
@@ -0,0 +1,25 @@
+#apiVersion: extensions/v1beta1 #changed
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: prometheus-ingress
+ namespace: monitoring
+ annotations:
+ kubernetes.io/ingress.class: "traefik"
+ labels:
+ app: prometheus
+spec:
+ rules:
+ - host: prom.kubernauts.local
+ http:
+ paths:
+ - path: /
+ pathType: Prefix #changed
+ backend:
+ #serviceName: prometheus-operated #changed
+ #servicePort: 9090 #changed
+ service:
+ name: prometheus-operated
+ port:
+ number: 9090
+
diff --git a/affinity-and-anti-affinity/README.md b/affinity-and-anti-affinity/README.md
new file mode 100644
index 00000000..9d387fa9
--- /dev/null
+++ b/affinity-and-anti-affinity/README.md
@@ -0,0 +1,449 @@
+Table of Contents
+=================
+
+- [Table of Contents](#table-of-contents)
+- [Affinity and anti-affinity](#affinity-and-anti-affinity)
+- [Node affinity](#node-affinity)
+- [Example: Assign Pods to Nodes using Node Affinity](#example-assign-pods-to-nodes-using-node-affinity)
+ - [Add a label to a node](#add-a-label-to-a-node)
+ - [Schedule a Pod using required node affinity](#schedule-a-pod-using-required-node-affinity)
+ - [Schedule a Pod using preferred node affinity](#schedule-a-pod-using-preferred-node-affinity)
+ - [Pod Affinity and Anti-Affinity Demo](#pod-affinity-and-anti-affinity-demo)
+ - [Conclusion](#conclusion)
+ - [nodeName](#nodename)
+ - [nodeSelector](#nodeselector)
+ - [Add a label to a node demo](#add-a-label-to-a-node-demo)
+ - [Create a pod that gets scheduled to your chosen node](#create-a-pod-that-gets-scheduled-to-your-chosen-node)
+ - [Create a pod that gets scheduled to specific node](#create-a-pod-that-gets-scheduled-to-specific-node)
+
+
+# Affinity and anti-affinity
+
+Affinity and anti-affinity expands the types of constraints you can define.Some of the benefits of affinity and anti-affinity include:
+
+- The affinity/anti-affinity language is more expressive. Affinity/anti-affinity gives you more control over the selection logic.
+
+- You can indicate that a rule is soft or preferred, so that the scheduler still schedules the Pod even if it can't find a matching node.
+
+- You can constrain a Pod using labels on other Pods running on the node (or other topological domain), instead of just node labels, which allows you to define rules for which Pods can be co-located on a node.
+
+
+The affinity feature consists of two types of affinity:
+
+- Node _affinity_ functions like the `nodeSelector` field but is more expressive and allows you to specify soft rules.
+Inter-pod _affinity/anti-affinity_ allows you to constrain Pods against labels on other Pods.
+
+# Node affinity
+
+Node affinity is conceptually similar to `nodeSelector`, allowing you to constrain which nodes your Pod can be scheduled on based on node labels. There are two types of node affinity:
+
+- `requiredDuringSchedulingIgnoredDuringExecution`: The scheduler can't schedule the Pod unless the rule is met. This functions like nodeSelector, but with a more expressive syntax.
+
+- `preferredDuringSchedulingIgnoredDuringExecution`: The scheduler tries to find a node that meets the rule. If a matching node is not available, the scheduler still schedules the Pod.
+
+![pod-with-node-affinity.png](/images/pod-with-node-affinity.png)
+
+In this example, the following rules apply:
+
+- The node must have a label with the key `topology.kubernetes.io/zone` and the value of that label must be either `antarctica-east1` or `antarctica-west1`.
+
+- The node preferably has a label with the key `another-node-label-key` and the value `another-node-label-value`.
+
+- You can use the `operator` field to specify a logical operator for Kubernetes to use when interpreting the rules. You can use following:
+
+ - In
+ - NotIn
+ - Exists
+ - DoesNotExist
+ - Gt
+ - Lt
+
+- `NotIn` and `DoesNotExist` allow you to define node anti-affinity behavior.
+
+# Example: Assign Pods to Nodes using Node Affinity
+
+## Add a label to a node
+
+1. List the nodes in your cluster, along with their labels:
+
+ ```
+ kubectl get nodes --show-labels
+ ```
+
+ The output is similar to this:
+
+ ```
+ NAME STATUS ROLES AGE VERSION LABELS
+ worker0 Ready 1d v1.13.0 ...,kubernetes.io/hostname=worker0
+ worker1 Ready 1d v1.13.0 ...,kubernetes.io/hostname=worker1
+ worker2 Ready 1d v1.13.0 ...,kubernetes.io/hostname=worker2
+ ```
+
+2. Choose one of your nodes, and add a label to it:
+
+ ```
+ kubectl label nodes disktype=ssd
+ ```
+
+ where `` is the name of your chosen node.
+
+3. Verify that your chosen node has a `disktype=ssd` label:
+
+ ```
+ kubectl get nodes --show-labels
+ ```
+
+ The output is similar to this:
+
+ ```
+ NAME STATUS ROLES AGE VERSION LABELS
+ worker0 Ready 1d v1.13.0 ...,disktype=ssd,kubernetes.io/hostname=worker0
+ worker1 Ready 1d v1.13.0 ...,kubernetes.io/hostname=worker1
+ worker2 Ready 1d v1.13.0 ...,kubernetes.io/hostname=worker2
+ ```
+
+ In the preceding output, you can see that the `worker0` node has a `disktype=ssd` label.
+
+
+## Schedule a Pod using required node affinity
+
+This manifest describes a Pod that has a `requiredDuringSchedulingIgnoredDuringExecution` node affinity,`disktype: ssd`. This means that the pod will get scheduled only on a node that has a `disktype=ssd` label.
+
+Please refer below `pod-nginx-required-affinity.yaml` file:
+
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+ name: nginx
+spec:
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: disktype
+ operator: In
+ values:
+ - ssd
+ containers:
+ - name: nginx
+ image: nginx
+```
+
+1. Apply the manifest to create a Pod that is scheduled onto your chosen node:
+
+ ```
+ kubectl apply -f pod-nginx-required-affinity.yaml
+ ```
+
+2. Verify that the pod is running on your chosen node:
+
+ ```
+ kubectl get pods --output=wide
+ ```
+
+ The output is similar to this:
+
+ ```
+ NAME READY STATUS RESTARTS AGE IP NODE
+ nginx 1/1 Running 0 13s 10.200.0.4 worker0
+ ```
+
+
+## Schedule a Pod using preferred node affinity
+
+This manifest describes a Pod that has a `preferredDuringSchedulingIgnoredDuringExecution` node affinity,`disktype: ssd`. This means that the pod will prefer a node that has a `disktype=ssd` label.
+
+Please refer below `pod-nginx-preferred-affinity.yaml` file:
+
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+ name: nginx
+spec:
+ affinity:
+ nodeAffinity:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ - weight: 1
+ preference:
+ matchExpressions:
+ - key: disktype
+ operator: In
+ values:
+ - ssd
+ containers:
+ - name: nginx
+ image: nginx
+```
+
+1. Apply the manifest to create a Pod that is scheduled onto your chosen node:
+
+ ```
+ kubectl apply -f pod-nginx-preferred-affinity.yaml
+ ```
+
+2. Verify that the pod is running on your chosen node:
+
+ ```shll
+ kubectl get pods --output=wide
+ ```
+
+ The output is similar to this:
+
+ ```
+ NAME READY STATUS RESTARTS AGE IP NODE
+ nginx 1/1 Running 0 13s 10.200.0.4 worker0
+ ```
+
+
+## Pod Affinity and Anti-Affinity Demo
+
+Let's assume we have a Redis cache for web applications and we need to run three replicas of Redis but we need to make sure that each replica runs on a different node, we make use of pod anti-affinity here.
+
+Redis deployment with pod anti-affinity rule, so that each replica lands on a different node:
+
+Please refer below `redis.yaml` file:
+
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: redis-cache
+spec:
+ selector:
+ matchLabels:
+ app: store
+ replicas: 3
+ template:
+ metadata:
+ labels:
+ app: store
+ spec:
+ affinity:
+ podAntiAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ - labelSelector:
+ matchExpressions:
+ - key: app
+ operator: In
+ values:
+ - store
+ topologyKey: "kubernetes.io/hostname"
+ containers:
+ - name: redis-server
+ image: redis:3.2-alpine
+```
+
+
+Create the deployment using the yaml file above:
+
+```
+kubectl create -f redis.yaml
+```
+
+Check the deployment status:
+
+```
+kubectl get deploy
+```
+
+Check if each pod is running on different node:
+
+```
+kubectl get pod -o=custom-columns=NODE:.spec.nodeName,NAME:.metadata.name
+```
+
+We noticed that each pod is running on a different node.
+
+Next, let’s assume we have a web server running and we need to make sure that each web server pod co-locates with each Redis cache pod, but at the same time, we need to make sure two web server pods don’t run on the same node, for this to happen we make use of pod affinity and pod anti-affinity both as below.
+
+Create the deployment file with affinity and anti-affinity rules:
+
+Please refer below `web-server.yaml` file:
+
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: web-server
+spec:
+ selector:
+ matchLabels:
+ app: web-store
+ replicas: 3
+ template:
+ metadata:
+ labels:
+ app: web-store
+ spec:
+ affinity:
+ podAntiAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ - labelSelector:
+ matchExpressions:
+ - key: app
+ operator: In
+ values:
+ - web-store
+ topologyKey: "kubernetes.io/hostname"
+ podAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ - labelSelector:
+ matchExpressions:
+ - key: app
+ operator: In
+ values:
+ - store
+ topologyKey: "kubernetes.io/hostname"
+ containers:
+ - name: web-app
+ image: nginx:1.16-alpine
+
+```
+
+Create the deployment:
+
+```
+kubectl create -f web-server.yaml
+```
+
+List the pods along with nodes and check that they are placed as required by rules:
+
+```
+kubectl get pod -o=custom-columns=NODE:.spec.nodeName,NAME:.metadata.name
+```
+
+We noticed that each web pod is co-located with a redis pod, and no two web pods are running on the same node; this was done by using pod affinity and anti-affinity rules.
+
+## Conclusion
+
+Affinity and anti-affinity provide flexible ways to schedule pods on nodes or place pods relative to other pods. You can use affinity rules to optimize the pod placement on worker nodes for performance, fault tolerance, or other complex scheduling requirements.
+
+## nodeName
+
+`nodeName` is a more direct form of node selection than affinity or `nodeSelector`.
+
+`nodeName` is a field in the Pod spec. If the `nodeName` field is not empty, the scheduler ignores the Pod and the kubelet on the named node tries to place the Pod on that node.
+
+Using `nodeName` overrules using `nodeSelector` or affinity and anti-affinity rules.
+
+Some of the limitations of using `nodeName` to select nodes are:
+
+- If the named node does not exist, the Pod will not run, and in some cases may be automatically deleted.
+
+- If the named node does not have the resources to accommodate the Pod, the Pod will fail and its reason will indicate why, for example OutOfmemory or OutOfcpu.
+
+- Node names in cloud environments are not always predictable or stable.
+
+Here is an example of a Pod spec using the `nodeName` field:
+
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+ name: nginx
+spec:
+ containers:
+ - name: nginx
+ image: nginx
+ nodeName: kube-01
+```
+
+The above Pod will only run on the node `kube-01`.
+
+## nodeSelector
+
+`nodeSelector` is the simplest recommended form of node selection constraint.
+
+You can add the `nodeSelector` field to your Pod specification and specify the node labels you want the target node to have. Kubernetes only schedules the Pod onto nodes that have each of the labels you specify.
+
+## Add a label to a node demo
+
+1. List the nodes in your cluster, along with their labels:
+
+```
+kubectl get nodes --show-labels
+```
+
+
+2. Choose one of your nodes, and add a label to it:
+
+ ```shell
+ kubectl label nodes disktype=ssd
+ ```
+
+ where `` is the name of your chosen node.
+
+3. Verify that your chosen node has a `disktype=ssd` label:
+
+ ```shell
+ kubectl get nodes --show-labels
+ ```
+
+ The output is similar to this:
+
+ ```shell
+ NAME STATUS ROLES AGE VERSION LABELS
+ worker0 Ready 1d v1.13.0 ...,disktype=ssd,kubernetes.io/hostname=worker0
+ worker1 Ready 1d v1.13.0 ...,kubernetes.io/hostname=worker1
+ worker2 Ready 1d v1.13.0 ...,kubernetes.io/hostname=worker2
+ ```
+
+ In the preceding output, you can see that the `worker0` node has a `disktype=ssd` label.
+
+
+## Create a pod that gets scheduled to your chosen node[](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-your-chosen-node)
+
+This pod configuration file describes a pod that has a node selector, `disktype: ssd`. This means that the pod will get scheduled on a node that has a `disktype=ssd` label.
+
+Please refer below `pod-nginx.yaml` file:
+
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+ name: nginx
+ labels:
+ env: test
+spec:
+ containers:
+ - name: nginx
+ image: nginx
+ imagePullPolicy: IfNotPresent
+ nodeSelector:
+ disktype: ssd
+```
+
+1. Use the configuration file to create a pod that will get scheduled on your chosen node:
+
+```
+kubectl apply -f pod-nginx.yaml
+```
+
+2. Verify that the pod is running on your chosen node:
+
+```
+kubectl get pods --output=wide
+```
+
+## Create a pod that gets scheduled to specific node
+
+You can also schedule a pod to one specific node via setting `nodeName`.
+
+Please refer below `pod-nginx-specific-node.yaml` file:
+
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+ name: nginx
+spec:
+ nodeName: foo-node # schedule pod to specific node
+ containers:
+ - name: nginx
+ image: nginx
+```
+
+Use the configuration file to create a pod that will get scheduled on `foo-node` only.
\ No newline at end of file
diff --git a/affinity-and-anti-affinity/pod-nginx-preferred-affinity.yaml b/affinity-and-anti-affinity/pod-nginx-preferred-affinity.yaml
new file mode 100644
index 00000000..449bc0fb
--- /dev/null
+++ b/affinity-and-anti-affinity/pod-nginx-preferred-affinity.yaml
@@ -0,0 +1,18 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: nginx
+spec:
+ affinity:
+ nodeAffinity:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ - weight: 1
+ preference:
+ matchExpressions:
+ - key: disktype
+ operator: In
+ values:
+ - ssd
+ containers:
+ - name: nginx
+ image: nginx
\ No newline at end of file
diff --git a/affinity-and-anti-affinity/pod-nginx-required-affinity.yaml b/affinity-and-anti-affinity/pod-nginx-required-affinity.yaml
new file mode 100644
index 00000000..2e72397b
--- /dev/null
+++ b/affinity-and-anti-affinity/pod-nginx-required-affinity.yaml
@@ -0,0 +1,17 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: nginx
+spec:
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: disktype
+ operator: In
+ values:
+ - ssd
+ containers:
+ - name: nginx
+ image: nginx
\ No newline at end of file
diff --git a/affinity-and-anti-affinity/pod-with-node-affinity.yml b/affinity-and-anti-affinity/pod-with-node-affinity.yml
new file mode 100644
index 00000000..7eb7b230
--- /dev/null
+++ b/affinity-and-anti-affinity/pod-with-node-affinity.yml
@@ -0,0 +1,26 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: with-node-affinity
+spec:
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: topology.kubernetes.io/zone
+ operator: In
+ values:
+ - antarctica-east1
+ - antarctica-west1
+ preferredDuringSchedulingIgnoredDuringExecution:
+ - weight: 1
+ preference:
+ matchExpressions:
+ - key: another-node-label-key
+ operator: In
+ values:
+ - another-node-label-value
+ containers:
+ - name: with-node-affinity
+ image: registry.k8s.io/pause:2.0
\ No newline at end of file
diff --git a/alpine-pod-2-containers.yaml b/alpine-pod-2-containers.yaml
new file mode 100644
index 00000000..4cbfd15b
--- /dev/null
+++ b/alpine-pod-2-containers.yaml
@@ -0,0 +1,26 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ #creationTimestamp: null
+ labels:
+ run: alpine-2-containers
+ name: alpine-2-containers
+spec:
+ containers:
+ - args:
+ - /bin/sh
+ - -c
+ - echo hello;sleep 10000
+ image: alpine
+ name: alpine1
+ #resources: {}
+ - args:
+ - /bin/sh
+ - -c
+ - echo hello;sleep 10000
+ image: alpine
+ name: alpine2
+ #resources: {}
+ dnsPolicy: ClusterFirst
+ restartPolicy: Never
+#status: {}
diff --git a/alpine-pod-service-account.yaml b/alpine-pod-service-account.yaml
new file mode 100644
index 00000000..c182125d
--- /dev/null
+++ b/alpine-pod-service-account.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ #creationTimestamp: null
+ labels:
+ run: alpine-sa
+ name: alpine-sa
+spec:
+ serviceAccountName: mysa
+ containers:
+ - args:
+ - /bin/sh
+ - -c
+ - echo hello;sleep 3600
+ image: alpine
+ name: alpine-2-containers
+ # resources: {}
+ dnsPolicy: ClusterFirst
+ restartPolicy: Never
+#status: {}
diff --git a/alpine-pod-share-volumes.yaml b/alpine-pod-share-volumes.yaml
new file mode 100644
index 00000000..7b447997
--- /dev/null
+++ b/alpine-pod-share-volumes.yaml
@@ -0,0 +1,32 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ labels:
+ run: alpine-2-containers
+ name: alpine-2-containers-share-volume
+spec:
+ containers:
+ - args:
+ - /bin/sh
+ - -c
+ - echo hello;sleep 10000
+ image: alpine
+ name: alpine1
+ volumeMounts:
+ - name: share
+ mountPath: "/tmp/share1"
+ - args:
+ - /bin/sh
+ - -c
+ - echo hello;sleep 10000
+ image: alpine
+ name: alpine2
+ volumeMounts:
+ - name: share
+ mountPath: "/tmp/share2"
+ dnsPolicy: ClusterFirst
+ restartPolicy: Never
+ volumes:
+ - name: share
+ emptyDir: {}
+#status: {}
diff --git a/alpine-pod.yaml b/alpine-pod.yaml
new file mode 100644
index 00000000..2c3b7aac
--- /dev/null
+++ b/alpine-pod.yaml
@@ -0,0 +1,19 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ #creationTimestamp: null
+ labels:
+ run: alpine-2-containers
+ name: alpine-2-containers
+spec:
+ containers:
+ - args:
+ - /bin/sh
+ - -c
+ - echo hello;sleep 3600
+ image: alpine
+ name: alpine-2-containers
+ #resources: {}
+ dnsPolicy: ClusterFirst
+ restartPolicy: Never
+#status: {}
diff --git a/cm-kubernauts.yaml b/cm-kubernauts.yaml
new file mode 100644
index 00000000..e97e8dac
--- /dev/null
+++ b/cm-kubernauts.yaml
@@ -0,0 +1,7 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ #creationTimestamp: null #changed
+ name: kubernauts
+data:
+ dev: ops
diff --git a/cool-links.md b/cool-links.md
new file mode 100644
index 00000000..917afeb8
--- /dev/null
+++ b/cool-links.md
@@ -0,0 +1,23 @@
+
+
+[Kubernetes and Container Run-times](https://medium.com/better-software/kubernetes-and-container-run-times-f13464f1f5c5)
+
+[Kubernetes Networking: Behind the scenes](https://itnext.io/kubernetes-networking-behind-the-scenes-39a1ab1792bb)
+
+[Injecting Secrets into Kubernetes Pods via Vault Helm Sidecar](https://learn.hashicorp.com/vault/getting-started-k8s/sidecar)
+
+[Kubernetes Patterns : Capacity Planning](https://www.magalix.com/blog/kubernetes-patterns-capacity-planning)
+
+[Understanding Kubernetes limits and requests by example](https://sysdig.com/blog/kubernetes-limits-requests)
+
+https://www.stackrox.com/post/2020/01/kubernetes-networking-demystified
+
+https://learnk8s.io/autoscaling-apps-kubernetes
+
+https://medium.com/better-programming/tutorial-how-to-use-kubernetes-job-and-cronjob-1ef4ffbc8e84
+
+https://blog.pipetail.io/posts/2020-05-04-most-common-mistakes-k8s/
+
+https://blog.marekbartik.com/posts/2018-06-29_kubernetes-in-production-poddisruptionbudget/
+
+https://medium.com/faun/kubernetes-ckad-weekly-challenge-5-secrets-und-configmaps-550afde679fe
diff --git a/cordon-and-drain/README.md b/cordon-and-drain/README.md
new file mode 100644
index 00000000..f09e081b
--- /dev/null
+++ b/cordon-and-drain/README.md
@@ -0,0 +1,37 @@
+- Cordon will mark the node as unschedulable.
+
+- Uncordon will mark the node as schedulable.
+
+- Once you cordon the given node, it will be marked as unschedulable to prevent new pods from scheduling.
+
+- We cannot schedule a new pod until the node is cordoned.
+
+- You can use `kubectl drain` to safely evict all of your pods from a node before you perform maintenance on the node (e.g. kernel upgrade, hardware maintenance, etc.).
+
+- Safe evictions allow the pod's containers to gracefully terminate.
+
+
+First, identify the name of the node you wish to drain. You can list all of the nodes in your cluster with:
+
+```
+kubectl get nodes
+```
+
+Next, tell Kubernetes to drain the node:
+
+```
+kubectl drain
+```
+
+Next, mark the node to not schedule new pods.
+
+```
+kubectl cordon
+```
+
+Once maintenance period is over, uncordon the node to schedule new pods.
+
+```
+kubectl uncordon
+```
+
diff --git a/dev b/dev
new file mode 100644
index 00000000..95534d00
--- /dev/null
+++ b/dev
@@ -0,0 +1 @@
+ops
\ No newline at end of file
diff --git a/docker/images/ghost/Dockerfile b/docker/images/ghost/Dockerfile
new file mode 100644
index 00000000..0f16e993
--- /dev/null
+++ b/docker/images/ghost/Dockerfile
@@ -0,0 +1,77 @@
+# https://docs.ghost.org/faq/node-versions/
+# https://github.com/nodejs/LTS
+# https://github.com/TryGhost/Ghost/blob/3.3.0/package.json#L38
+FROM node:12-alpine3.11
+
+# grab su-exec for easy step-down from root
+RUN apk add --no-cache 'su-exec>=0.2'
+
+RUN apk add --no-cache \
+# add "bash" for "[["
+ bash
+
+ENV NODE_ENV production
+
+ENV GHOST_CLI_VERSION 1.14.1
+RUN set -eux; \
+ npm install -g "ghost-cli@$GHOST_CLI_VERSION"; \
+ npm cache clean --force
+
+ENV GHOST_INSTALL /var/lib/ghost
+ENV GHOST_CONTENT /var/lib/ghost/content
+
+ENV GHOST_VERSION 3.25.0
+
+RUN set -eux; \
+ mkdir -p "$GHOST_INSTALL"; \
+ chown node:node "$GHOST_INSTALL"; \
+ \
+ su-exec node ghost install "$GHOST_VERSION" --db sqlite3 --no-prompt --no-stack --no-setup --dir "$GHOST_INSTALL"; \
+ \
+# Tell Ghost to listen on all ips and not prompt for additional configuration
+ cd "$GHOST_INSTALL"; \
+ su-exec node ghost config --ip 0.0.0.0 --port 2368 --no-prompt --db sqlite3 --url http://localhost:2368 --dbpath "$GHOST_CONTENT/data/ghost.db"; \
+ su-exec node ghost config paths.contentPath "$GHOST_CONTENT"; \
+ \
+# make a config.json symlink for NODE_ENV=development (and sanity check that it's correct)
+ su-exec node ln -s config.production.json "$GHOST_INSTALL/config.development.json"; \
+ readlink -f "$GHOST_INSTALL/config.development.json"; \
+ \
+# need to save initial content for pre-seeding empty volumes
+ mv "$GHOST_CONTENT" "$GHOST_INSTALL/content.orig"; \
+ mkdir -p "$GHOST_CONTENT"; \
+ chown node:node "$GHOST_CONTENT"; \
+ \
+# force install "sqlite3" manually since it's an optional dependency of "ghost"
+# (which means that if it fails to install, like on ARM/ppc64le/s390x, the failure will be silently ignored and thus turn into a runtime error instead)
+# see https://github.com/TryGhost/Ghost/pull/7677 for more details
+ cd "$GHOST_INSTALL/current"; \
+# scrape the expected version of sqlite3 directly from Ghost itself
+ sqlite3Version="$(node -p 'require("./package.json").optionalDependencies.sqlite3')"; \
+ if ! su-exec node yarn add "sqlite3@$sqlite3Version" --force; then \
+# must be some non-amd64 architecture pre-built binaries aren't published for, so let's install some build deps and do-it-all-over-again
+ apk add --no-cache --virtual .build-deps python make gcc g++ libc-dev; \
+ \
+ su-exec node yarn add "sqlite3@$sqlite3Version" --force --build-from-source; \
+ \
+ apk del --no-network .build-deps; \
+ fi; \
+ \
+ su-exec node yarn cache clean; \
+ su-exec node npm cache clean --force; \
+ npm cache clean --force; \
+ rm -rv /tmp/yarn* /tmp/v8*
+
+WORKDIR $GHOST_INSTALL
+VOLUME $GHOST_CONTENT
+
+COPY docker-entrypoint.sh /usr/local/bin
+ENTRYPOINT ["docker-entrypoint.sh"]
+
+ENV USER=node
+ENV UID=12345
+
+USER node
+
+EXPOSE 2368
+CMD ["node", "current/index.js"]
\ No newline at end of file
diff --git a/docker/images/ghost/README.md b/docker/images/ghost/README.md
new file mode 100644
index 00000000..69e20cda
--- /dev/null
+++ b/docker/images/ghost/README.md
@@ -0,0 +1,3 @@
+# Ghost dockerfile
+
+this ghost dockerfile builds the ghost image with the user node for security reasons
diff --git a/docker/images/ghost/docker-entrypoint.sh b/docker/images/ghost/docker-entrypoint.sh
new file mode 100755
index 00000000..c4d007b5
--- /dev/null
+++ b/docker/images/ghost/docker-entrypoint.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+set -e
+
+# allow the container to be started with `--user`
+if [[ "$*" == node*current/index.js* ]] && [ "$(id -u)" = '0' ]; then
+ find "$GHOST_CONTENT" \! -user node -exec chown node '{}' +
+ exec su-exec node "$BASH_SOURCE" "$@"
+fi
+
+if [[ "$*" == node*current/index.js* ]]; then
+ baseDir="$GHOST_INSTALL/content.orig"
+ for src in "$baseDir"/*/ "$baseDir"/themes/*; do
+ src="${src%/}"
+ target="$GHOST_CONTENT/${src#$baseDir/}"
+ mkdir -p "$(dirname "$target")"
+ if [ ! -e "$target" ]; then
+ tar -cC "$(dirname "$src")" "$(basename "$src")" | tar -xC "$(dirname "$target")"
+ fi
+ done
+fi
+
+exec "$@"
diff --git a/elastic-stack/README.md b/elastic-stack/README.md
new file mode 100644
index 00000000..0721e750
--- /dev/null
+++ b/elastic-stack/README.md
@@ -0,0 +1,387 @@
+Table of Contents
+=================
+
+ * [What is Elasticsearch?](#what-is-elasticsearch)
+ * [What is Elasticsearch used for?](#what-is-elasticsearch-used-for)
+ * [How does Elasticsearch work?](#how-does-elasticsearch-work)
+ * [What is an Elasticsearch index?](#what-is-an-elasticsearch-index)
+ * [What is Kibana used for?](#what-is-kibana-used-for)
+ * [What is Fluent Bit?](#what-is-fluent-bit)
+ * [How Fluent Bit works?](#how-fluent-bit-works)
+ * [Set up Kubernetes Cluster for Elasticsearch](#set-up-kubernetes-cluster-for-elasticsearch)
+ * [Deploy Elasticsearch with Helm](#deploy-elasticsearch-with-helm)
+ * [Install Kibana](#install-kibana)
+ * [Install Fluent Bit](#install-fluent-bit)
+ * [Reference links](#reference-links)
+
+
+## What is Elasticsearch?
+
+Elasticsearch is a distributed, RESTful search and analytics engine capable of addressing a growing number of use cases.
+
+- Add a search box to an app or website
+- Store and analyze logs, metrics, and security event data
+- Use machine learning to automatically model the behavior of your data in real time
+- Automate business workflows using Elasticsearch as a storage engine
+- Manage, integrate, and analyze spatial information using Elasticsearch as a geographic information system (GIS)
+- Store and process genetic data using Elasticsearch as a bioinformatics research tool
+
+As the heart of the free and open Elastic Stack, it centrally stores your data for lightning fast search, fine‑tuned relevancy, and powerful analytics that scale with ease.
+
+Kibana enables you to interactively explore, visualize, and share insights into your data and manage and monitor the stack.
+
+Elasticsearch is where the indexing, search, and analysis magic happens.
+
+## What is Elasticsearch used for?
+
+The speed and scalability of Elasticsearch and its ability to index many types of content mean that it can be used for a number of use cases:
+
+- Application search
+- Website search
+- Enterprise search
+- Logging and log analytics
+- Infrastructure metrics and container monitoring
+- Application performance monitoring
+- Geospatial data analysis and visualization
+- Security analytics
+- Business analytics
+
+## How does Elasticsearch work?
+
+Raw data flows into Elasticsearch from a variety of sources, including logs, system metrics, and web applications. _Data ingestion_ is the process by which this raw data is parsed, normalized, and enriched before it is _indexed_ in Elasticsearch.
+
+Once indexed in Elasticsearch, users can run complex queries against their data and use aggregations to retrieve complex summaries of their data.
+
+From Kibana, users can create powerful visualizations of their data, share dashboards, and manage the Elastic Stack.
+
+## What is an Elasticsearch index?
+
+An Elasticsearch _index_ is a collection of documents that are related to each other.
+
+Elasticsearch stores data as **JSON documents**.
+
+Each document correlates a set of _keys_ (names of fields or properties) with their corresponding values (strings, numbers, Booleans, dates, arrays of _values_, geolocations, or other types of data).
+
+Elasticsearch uses a data structure called an _inverted index_, which is designed to allow very fast full-text searches.
+
+An inverted index lists every unique word that appears in any document and identifies all of the documents each word occurs in.
+
+During the indexing process, Elasticsearch stores documents and builds an inverted index to make the document data searchable in near real-time.
+
+Indexing is initiated with the index API, through which you can add or update a JSON document in a specific index.
+
+## What is Kibana used for?
+
+Kibana is a data visualization and management tool for Elasticsearch that provides real-time histograms, line graphs, pie charts, and maps.
+
+Kibana also includes advanced applications such as Canvas, which allows users to create custom dynamic infographics based on their data, and Elastic Maps for visualizing geospatial data.
+
+## What is Fluent Bit?
+
+Fluent Bit is an open source and multi-platform log processor tool which aims to be a generic Swiss knife for logs processing and distribution.
+
+Nowadays the number of sources of information in our environments is ever increasing.
+
+Handling data collection at scale is complex, and collecting and aggregating diverse data requires a specialized tool that can deal with:
+
+- Different sources of information
+- Different data formats
+- Data Reliability
+- Security
+- Flexible Routing
+- Multiple destinations
+
+Fluent Bit has been designed with performance and low resources consumption in mind.
+
+
+## How Fluent Bit works?
+
+![How fluent bit works](/images/fluentbit-works.png)
+
+The above image represents the life cycle overview how messages are passed from various components in the Fluent Bit.
+
+- Input : Gathers information from different sources, some of them just collect data from log files while others can gather metrics information from the operating system. There are many plugins for different needs.
+
+- Parser : Dealing with raw strings or unstructured messages is a constant pain; having a structure is highly desired. Ideally we want to set a structure to the incoming data by the Input Plugins as soon as they are collected.
+
+unstructured data:
+
+```
+192.168.2.20 - - [28/Jul/2006:10:27:10 -0300] "GET /cgi-bin/try/ HTTP/1.0" 200 3395
+```
+
+structured data:
+
+```
+{
+ "host": "192.168.2.20",
+ "user": "-",
+ "method": "GET",
+ "path": "/cgi-bin/try/",
+ "code": "200",
+ "size": "3395",
+ "referer": "",
+ "agent": ""
+ }
+ ```
+
+- Filter : In production environments we want to have full control of the data we are collecting, filtering is an important feature that allows us to alter the data before delivering it to some destination.
+
+- Buffer : Fluent Bit offers a buffering mechanism in the file system that acts as a backup system to avoid data loss in case of system failures.
+
+- Router : Routing is a core feature that allows to route your data through Filters and finally to one or multiple destinations. The router relies on the concept of `Tags` and `Matching rules`.
+
+- Output : The output interface allows us to define destinations for the data. Common destinations are remote services, local file system or standard interface with others. Outputs are implemented as plugins and there are many available.
+
+## Set up Kubernetes Cluster for Elasticsearch
+
+Check if your cluster is functioning properly by typing:
+
+```
+kubectl cluster-info
+```
+
+Output:
+
+```Output
+Kubernetes control plane is running at https://127.0.0.1:38187
+CoreDNS is running at https://127.0.0.1:38187/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
+
+To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
+```
+
+## Deploy Elasticsearch with Helm
+
+```
+helm repo add elastic https://helm.elastic.co
+```
+
+Now, use the **`curl`** command to download the **`values.yaml`** file containing configuration information:
+
+```
+curl -O https://raw.githubusercontent.com/elastic/helm-charts/main/elasticsearch/examples/kubernetes-kind/values-local-path.yaml
+```
+
+Output:
+
+```Output
+% Total % Received % Xferd Average Speed Time Time Time Current
+ Dload Upload Total Spent Left Speed
+100 480 100 480 0 0 1075 0 --:--:-- --:--:-- --:--:-- 1076
+```
+
+Here, we have defined persistent-volume yaml file:
+
+```
+apiVersion: v1
+
+kind: PersistentVolume
+
+metadata:
+
+ labels:
+
+ type: hostpath
+
+ name: elasticsearch-data-quickstart-es-default-0
+
+spec:
+
+ accessModes:
+
+ - ReadWriteMany
+
+ capacity:
+
+ storage: 2Gi
+
+ claimRef:
+
+ apiVersion: v1
+
+ kind: PersistentVolumeClaim
+
+ name: elasticsearch-data-quickstart-es-default-0
+
+ namespace: elasticsearch
+
+ hostPath:
+
+ path: /tmp/mypvsc
+
+ type: DirectoryOrCreate
+
+ persistentVolumeReclaimPolicy: Delete
+
+ storageClassName: mypvsc
+
+ volumeMode: Filesystem
+```
+
+```
+k apply -f pv.yaml
+```
+
+Deploy Elasticsearch chart:
+
+```
+helm install elasticsearch elastic/elasticsearch -f ./values-local-path.yaml
+```
+
+Run the **`helm test`** command to examine the cluster’s health:
+
+```
+helm test elasticsearch
+```
+
+Output:
+
+```Output
+
+NAME: elasticsearch
+LAST DEPLOYED: Mon Oct 31 12:15:14 2022
+NAMESPACE: elasticsearch
+STATUS: deployed
+REVISION: 1
+TEST SUITE: elasticsearch-mpxoc-test
+Last Started: Mon Oct 31 12:20:11 2022
+Last Completed: Mon Oct 31 12:20:15 2022
+Phase: Succeeded
+NOTES:
+1. Watch all cluster members come up.
+ $ kubectl get pods --namespace=elasticsearch -l app=elasticsearch-master -w2. Test cluster health using Helm test.
+ $ helm --namespace=elasticsearch test elasticsearch
+```
+
+
+Once you successfully installed Elasticsearch, use the `kubectl port-forward` command to forward it to **port 9200**:
+
+```
+kubectl port-forward svc/elasticsearch-master 9200
+```
+
+Run `127.0.0.1:9200` in URL box in browser:
+
+Output:
+
+```Output
+{
+ "name" : "elasticsearch-master-1",
+ "cluster_name" : "elasticsearch",
+ "cluster_uuid" : "Yi_QDvdiQoWtG8eNrNtEgQ",
+ "version" : {
+ "number" : "7.17.3",
+ "build_flavor" : "default",
+ "build_type" : "docker",
+ "build_hash" : "5ad023604c8d7416c9eb6c0eadb62b14e766caff",
+ "build_date" : "2022-04-19T08:11:19.070913226Z",
+ "build_snapshot" : false,
+ "lucene_version" : "8.11.1",
+ "minimum_wire_compatibility_version" : "6.8.0",
+ "minimum_index_compatibility_version" : "6.0.0-beta1"
+ },
+ "tagline" : "You Know, for Search"
+}
+```
+
+## Install Kibana
+
+1. To install Kibana on top of Elasticsearch, type the following command:
+
+```
+helm install kibana elastic/kibana
+```
+
+The output confirms the deployment of Kibana:
+
+```Output
+NAME: kibana
+LAST DEPLOYED: Mon Oct 31 12:36:25 2022
+NAMESPACE: elasticsearch
+STATUS: deployed
+REVISION: 1
+TEST SUITE: None
+```
+
+2. Check if all the pods are ready:
+
+```
+kubectl get pods
+```
+
+Kibana pod appears underneath the Elasticsearch pods:
+
+```
+NAME READY STATUS RESTARTS AGE
+elasticsearch-master-0 1/1 Running 0 22m
+elasticsearch-master-1 1/1 Running 0 22m
+elasticsearch-master-2 1/1 Running 0 22m
+kibana-kibana-95dc995b9-s9kj7 1/1 Running 0 87s
+```
+
+OR
+We can check the Kibana deployment:
+
+```
+kubectl get deployments
+```
+
+Output:
+
+```Output
+NAME READY UP-TO-DATE AVAILABLE AGE
+kibana-kibana 1/1 1 1 2m4s
+```
+
+3. Forward Kibana to **port 5601** using **`kubectl`**:
+
+```
+kubectl port-forward deployment/kibana-kibana 5601
+```
+
+4. Setting up port-forwarding, access Elasticsearch and the Kibana GUI by typing in URL box:
+
+```
+http://127.0.0.1:5601
+```
+
+## Install Fluent Bit
+
+1. To add the fluent helm repo, run:
+
+```
+helm repo add fluent https://fluent.github.io/helm-charts
+```
+
+2. To install a release named fluent-bit, run:
+
+```
+helm install fluent-bit fluent/fluent-bit
+```
+
+3. To see fluent-bit DaemonSet:
+
+```
+kubectl get ds
+```
+
+4. Visit [Kibana](http://127.0.0.1:5601). You will now be able to create an index pattern. Navigate to **`Management`** > **`Stack Management`** > **`Index patterns`**:
+
+![Index-Pattern.png](/images/Index-Pattern.png)
+
+![Create-Index-Pattern.png](/images/Create-Index-Pattern.png)
+
+5. Click the **`Create Index Pattern`** button to start working with Kibana.
+6. Go to the **Analytics** > **Discover** to visualize the logs:
+
+![Discover-logs](/images/Discover-logs.png)
+
+
+## Reference links
+
+[What is Elasticsearch?](https://www.elastic.co/what-is/elasticsearch)
+
+[Elasticsearch Guide](https://www.elastic.co/guide/en/elasticsearch/reference/current/elasticsearch-intro.html)
+
+[Fluent Bit docs](https://docs.fluentbit.io/manual/)
+
diff --git a/elastic-stack/pv.yaml b/elastic-stack/pv.yaml
new file mode 100644
index 00000000..9107c30f
--- /dev/null
+++ b/elastic-stack/pv.yaml
@@ -0,0 +1,22 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ labels:
+ type: hostpath
+ name: elasticsearch-data-quickstart-es-default-0
+spec:
+ accessModes:
+ - ReadWriteMany
+ capacity:
+ storage: 2Gi
+ claimRef:
+ apiVersion: v1
+ kind: PersistentVolumeClaim
+ name: elasticsearch-data-quickstart-es-default-0
+ namespace: elasticsearch
+ hostPath:
+ path: /tmp/mypvsc
+ type: DirectoryOrCreate
+ persistentVolumeReclaimPolicy: Delete
+ storageClassName: mypvsc
+ volumeMode: Filesystem
diff --git a/elastic-stack/values-local-path.yaml b/elastic-stack/values-local-path.yaml
new file mode 100644
index 00000000..500ad4b1
--- /dev/null
+++ b/elastic-stack/values-local-path.yaml
@@ -0,0 +1,23 @@
+---
+# Permit co-located instances for solitary minikube virtual machines.
+antiAffinity: "soft"
+
+# Shrink default JVM heap.
+esJavaOpts: "-Xmx128m -Xms128m"
+
+# Allocate smaller chunks of memory per pod.
+resources:
+ requests:
+ cpu: "100m"
+ memory: "512M"
+ limits:
+ cpu: "1000m"
+ memory: "512M"
+
+# Request smaller persistent volumes.
+volumeClaimTemplate:
+ accessModes: [ "ReadWriteOnce" ]
+ storageClassName: "local-path"
+ resources:
+ requests:
+ storage: 100M
diff --git a/images/Create-Index-Pattern-Opensearch-Operator.png b/images/Create-Index-Pattern-Opensearch-Operator.png
new file mode 100644
index 00000000..18b9f6af
Binary files /dev/null and b/images/Create-Index-Pattern-Opensearch-Operator.png differ
diff --git a/images/Create-Index-Pattern-Opensearch.png b/images/Create-Index-Pattern-Opensearch.png
new file mode 100644
index 00000000..d232c992
Binary files /dev/null and b/images/Create-Index-Pattern-Opensearch.png differ
diff --git a/images/Create-Index-Pattern-Operator.png b/images/Create-Index-Pattern-Operator.png
new file mode 100644
index 00000000..2fe749f9
Binary files /dev/null and b/images/Create-Index-Pattern-Operator.png differ
diff --git a/images/Create-Index-Pattern.png b/images/Create-Index-Pattern.png
new file mode 100644
index 00000000..df3a3a44
Binary files /dev/null and b/images/Create-Index-Pattern.png differ
diff --git a/images/Defined-Index-Pattern-2-Opensearch.png b/images/Defined-Index-Pattern-2-Opensearch.png
new file mode 100644
index 00000000..9c89c8af
Binary files /dev/null and b/images/Defined-Index-Pattern-2-Opensearch.png differ
diff --git a/images/Defined-Index-Pattern-Opensearch-Operator.png b/images/Defined-Index-Pattern-Opensearch-Operator.png
new file mode 100644
index 00000000..24409bd9
Binary files /dev/null and b/images/Defined-Index-Pattern-Opensearch-Operator.png differ
diff --git a/images/Defined-Index-Pattern-Opensearch.png b/images/Defined-Index-Pattern-Opensearch.png
new file mode 100644
index 00000000..c169ad0b
Binary files /dev/null and b/images/Defined-Index-Pattern-Opensearch.png differ
diff --git a/images/Discover-logs-Opensearch-Operator.png b/images/Discover-logs-Opensearch-Operator.png
new file mode 100644
index 00000000..2ae061cf
Binary files /dev/null and b/images/Discover-logs-Opensearch-Operator.png differ
diff --git a/images/Discover-logs-Opensearch.png b/images/Discover-logs-Opensearch.png
new file mode 100644
index 00000000..fa8a1112
Binary files /dev/null and b/images/Discover-logs-Opensearch.png differ
diff --git a/images/Discover-logs.png b/images/Discover-logs.png
new file mode 100644
index 00000000..f5fd7e68
Binary files /dev/null and b/images/Discover-logs.png differ
diff --git a/images/Index-Pattern.png b/images/Index-Pattern.png
new file mode 100644
index 00000000..3d601713
Binary files /dev/null and b/images/Index-Pattern.png differ
diff --git a/images/IngressFanOut.png b/images/IngressFanOut.png
new file mode 100644
index 00000000..4ef03dff
Binary files /dev/null and b/images/IngressFanOut.png differ
diff --git a/images/OpenSearch-REST-API-curl.png b/images/OpenSearch-REST-API-curl.png
new file mode 100644
index 00000000..7c975ba1
Binary files /dev/null and b/images/OpenSearch-REST-API-curl.png differ
diff --git a/images/OpenSearch-REST-API.png b/images/OpenSearch-REST-API.png
new file mode 100644
index 00000000..166830a8
Binary files /dev/null and b/images/OpenSearch-REST-API.png differ
diff --git a/images/deploy.png b/images/deploy.png
new file mode 100644
index 00000000..e3fb23dd
Binary files /dev/null and b/images/deploy.png differ
diff --git a/images/ep.png b/images/ep.png
new file mode 100644
index 00000000..d90c26e6
Binary files /dev/null and b/images/ep.png differ
diff --git a/images/fluentbit-works.png b/images/fluentbit-works.png
new file mode 100644
index 00000000..118957e2
Binary files /dev/null and b/images/fluentbit-works.png differ
diff --git a/images/headless-cluster-ip.png b/images/headless-cluster-ip.png
new file mode 100644
index 00000000..5b52f398
Binary files /dev/null and b/images/headless-cluster-ip.png differ
diff --git a/images/hpa.png b/images/hpa.png
new file mode 100644
index 00000000..8834b8e4
Binary files /dev/null and b/images/hpa.png differ
diff --git a/images/icons-all.png b/images/icons-all.png
new file mode 100644
index 00000000..347bdd7a
Binary files /dev/null and b/images/icons-all.png differ
diff --git a/images/ing.png b/images/ing.png
new file mode 100644
index 00000000..d03982f3
Binary files /dev/null and b/images/ing.png differ
diff --git a/images/ingress-controller-traefik.png b/images/ingress-controller-traefik.png
new file mode 100644
index 00000000..41b481e3
Binary files /dev/null and b/images/ingress-controller-traefik.png differ
diff --git a/images/ingress.png b/images/ingress.png
new file mode 100644
index 00000000..2f0ebd96
Binary files /dev/null and b/images/ingress.png differ
diff --git a/images/ingressnamebased.png b/images/ingressnamebased.png
new file mode 100644
index 00000000..b39c83de
Binary files /dev/null and b/images/ingressnamebased.png differ
diff --git a/images/k8s-resources-map.png b/images/k8s-resources-map.png
new file mode 100644
index 00000000..371ba159
Binary files /dev/null and b/images/k8s-resources-map.png differ
diff --git a/images/opensearch-cluster-status.png b/images/opensearch-cluster-status.png
new file mode 100644
index 00000000..0f25c448
Binary files /dev/null and b/images/opensearch-cluster-status.png differ
diff --git a/images/pod-autoscaling-hpa.png b/images/pod-autoscaling-hpa.png
new file mode 100644
index 00000000..7c149d3e
Binary files /dev/null and b/images/pod-autoscaling-hpa.png differ
diff --git a/images/pod-with-node-affinity.png b/images/pod-with-node-affinity.png
new file mode 100644
index 00000000..c15632c1
Binary files /dev/null and b/images/pod-with-node-affinity.png differ
diff --git a/images/pod.png b/images/pod.png
new file mode 100644
index 00000000..c714505a
Binary files /dev/null and b/images/pod.png differ
diff --git a/images/prometheus-architecture.png b/images/prometheus-architecture.png
new file mode 100644
index 00000000..e8a21d31
Binary files /dev/null and b/images/prometheus-architecture.png differ
diff --git a/images/quota.png b/images/quota.png
new file mode 100644
index 00000000..ad308316
Binary files /dev/null and b/images/quota.png differ
diff --git a/images/rbac.png b/images/rbac.png
new file mode 100644
index 00000000..d408f18f
Binary files /dev/null and b/images/rbac.png differ
diff --git a/images/rs.png b/images/rs.png
new file mode 100644
index 00000000..61acd202
Binary files /dev/null and b/images/rs.png differ
diff --git a/images/svc.png b/images/svc.png
new file mode 100644
index 00000000..609cc279
Binary files /dev/null and b/images/svc.png differ
diff --git a/images/traefik.png b/images/traefik.png
new file mode 100644
index 00000000..7cce508f
Binary files /dev/null and b/images/traefik.png differ
diff --git a/images/unitsofmeasures.png b/images/unitsofmeasures.png
new file mode 100644
index 00000000..821241e0
Binary files /dev/null and b/images/unitsofmeasures.png differ
diff --git a/includes/create-configmap.md b/includes/create-configmap.md
new file mode 100644
index 00000000..c5aab948
--- /dev/null
+++ b/includes/create-configmap.md
@@ -0,0 +1,37 @@
+```
+k create cm kubernauts --from-literal=dev=ops --dry-run -o yaml > cm-kubernauts.yaml
+```
+
+```
+cat cm-kubernauts.yaml
+```
+
+```
+echo -n "ops" > dev
+```
+
+```
+k create cm kubernauts --from-file=./dev
+```
+
+```
+k get cm
+```
+
+```
+k describe cm kubernauts
+```
+
+```
+k delete cm kubernauts
+```
+
+```
+k create -f cm-kubernauts.yaml
+```
+
+```
+k describe cm kubernauts
+```
+
+
diff --git a/includes/create-deployments.md b/includes/create-deployments.md
new file mode 100644
index 00000000..d0db9002
--- /dev/null
+++ b/includes/create-deployments.md
@@ -0,0 +1,86 @@
+```
+k create --dry-run -o yaml >
+```
+
+```
+k create deployment nginx-deployment --image=nginx --dry-run -o yaml > nginx-deployment.yaml
+```
+
+```
+cat nginx-deployment.yaml
+```
+
+```
+k create -f nginx-pod.yaml
+```
+
+# create a service via exposing the pod
+
+```
+k expose pod nginx-pod --port=80
+```
+
+```
+k get svc
+```
+
+```
+k port-forward service/nginx-pod 8080:80
+```
+
+or
+
+```
+k proxy
+```
+
+```
+open http://127.0.0.1:8001/api/v1/namespaces/default/pods/nginx-pod/proxy/
+```
+
+# open a new terminal session
+
+```
+curl http://127.0.0.1:8080/
+```
+
+```
+k delete all --all # with caution!!!
+```
+
+```
+k create -f nginx-deployment.yaml
+```
+
+```
+k get all
+```
+
+```
+k get all -A
+```
+
+```
+k expose deployment nginx-deployment --port=80
+```
+
+```
+k port-forward service/nginx-deployment 8080:80
+```
+
+```
+k scale --replicas 3 deployment nginx-deployment
+```
+
+```
+k edit deployment nginx-deployment
+```
+
+```
+vi nginx-deployment.yaml # adapt the number of replicas, e.g. to 2
+```
+
+```
+k apply -f nginx-deployment.yaml
+```
+
diff --git a/includes/create-pods.md b/includes/create-pods.md
new file mode 100644
index 00000000..eb02a6f8
--- /dev/null
+++ b/includes/create-pods.md
@@ -0,0 +1,44 @@
+# old school (going to get deprecated)
+
+```
+k run --generator=run-pod/v1 --image= --dry-run -o yaml >
+```
+
+```
+k run --generator=run-pod/v1 "nginx-pod" --image=nginx -o yaml --dry-run > nginx-pod.yaml
+```
+
+or
+
+```
+k run --restart=Never --image= --dry-run -o yaml >
+```
+
+or
+
+```
+(new school with --dry-run=client)
+```
+
+```
+k run nginx-pod --image=nginx -o yaml --dry-run=client > nginx-pod.yaml
+```
+
+```
+k create -f nginx-pod.yaml
+```
+
+```
+k describe pod nginx-pod
+```
+
+```
+k get events
+```
+
+or
+
+```
+kgel
+```
+
diff --git a/includes/create-secrets.md b/includes/create-secrets.md
new file mode 100644
index 00000000..ce4b9214
--- /dev/null
+++ b/includes/create-secrets.md
@@ -0,0 +1,36 @@
+```
+echo -n "yourvalue" > ./secret.txt
+```
+
+```
+k create secret generic secretname --from-file=./secret.txt
+```
+
+```
+k describe secrets secretname
+```
+
+```
+k get secret secretname -o yaml
+```
+
+```
+echo 'eW91cnZhbHVl' | base64 --decode
+```
+
+# or
+
+```
+k create secret generic mysecret --dry-run -o yaml --from-file=./secret.txt > secret.yaml
+```
+
+```
+k create -f secret.yaml
+```
+
+# or
+
+```
+k create secret generic mysecret --dry-run -o yaml --from-literal=secret.txt=yourvalue > secret.yaml
+```
+
diff --git a/includes/get-events-logs.md b/includes/get-events-logs.md
new file mode 100644
index 00000000..d9470d61
--- /dev/null
+++ b/includes/get-events-logs.md
@@ -0,0 +1,121 @@
+```
+kx
+```
+
+```
+kn
+```
+
+```
+k delete all --all # with caution!!!
+```
+
+```
+k apply -f 0-nginx-all.yaml
+```
+
+```
+k get all
+```
+
+
+# where is the ingress?
+
+
+```
+k get ingress # ingress objects are not namespaced
+```
+
+```
+k get events
+```
+
+```
+k get events -A
+```
+
+```
+k get events --sort-by=.metadata.creationTimestamp # List Events sorted by timestamp
+```
+
+```
+k get events -n
+```
+
+```
+k logs nginx-
+```
+
+```
+k describe pod nginx-
+```
+
+```
+k describe deployment nginx
+```
+
+```
+k describe replicasets nginx-
+```
+
+```
+k get services --sort-by=.metadata.name # List Services Sorted by Name
+```
+
+```
+k get pods --sort-by=.metadata.name
+```
+
+```
+k get endpoints
+```
+
+```
+k explain pods,svc
+```
+
+```
+k get pods -A # --all-namespaces
+```
+
+```
+k get nodes -o jsonpath='{.items[*].spec.podCIDR}'
+```
+
+```
+k get pods -o wide
+```
+```
+k get pod my-pod -o yaml --export > my-pod.yaml # Get a pod's YAML without cluster
+specific information
+```
+
+```
+k get pods --show-labels # Show labels for all pods (or other objects)
+```
+
+```
+k get pods --sort-by='.status.containerStatuses[0].restartCount'
+```
+
+```
+k cluster-info
+```
+
+```
+k api-resources
+```
+
+```
+k api-resources -o wide
+```
+
+```
+kubectl api-resources --verbs=list,get # All resources that support the "list" and "get"
+request verbs
+```
+
+```
+k get apiservice
+```
+
diff --git a/includes/headless.md b/includes/headless.md
new file mode 100644
index 00000000..0ab09d9d
--- /dev/null
+++ b/includes/headless.md
@@ -0,0 +1,86 @@
+```
+k delete svc kubia
+```
+
+```
+k expose deployment kubia --name kubia-headless --cluster-ip None
+```
+
+```
+k expose deployment kubia --name kubia-clusterip
+```
+
+```
+k expose deployment kubia --name kubia-lb --type=LoadBalancer
+```
+
+```
+k scale deployment kubia --replicas 3
+```
+
+```
+k run --generator=run-pod/v1 utils -it --image kubernautslabs/utils -- bash
+```
+
+
+### inside the utils container
+
+```
+host kubia-headless
+```
+
+```
+host kubia-clusterip
+```
+
+
+### what is the difference here?
+
+```
+for i in $(seq 1 10) ; do curl kubia-headless:8080; done
+```
+
+### hits kubia only on one node?
+
+```
+for i in $(seq 1 10) ; do curl kubia-clusterip:8080; done
+```
+
+### does load balancing via the head ;-)
+
+```
+exit
+```
+
+```
+mkcert '*.whereami.svc'
+```
+```
+k create secret tls whereami-secret --cert=_wildcard.whereami.svc.pem --key=_wildcard.
+whereami.svc-key.pem
+```
+
+```
+cat kubia-ingress-tls.yaml
+```
+
+```
+k create -f kubia-ingress-tls.yaml
+```
+
+### Please provide the host entry mapping in your /etc/hosts file like this:
+
+
+### 192.168.64.23 my.whereami.svc
+
+### the IP should be the IP of the traefik loadbalancer / ingress controller
+
+```
+curl https://my.whereami.svc
+```
+
+```
+for i in $(seq 1 10) ; do curl https://my.whereami.svc; done
+```
+
+### the ingress controller does load balancing, although the kubia-headless is defined as the backend with serviceName: kubia-headless!
diff --git a/includes/ingress-tls.md b/includes/ingress-tls.md
new file mode 100644
index 00000000..bac6393e
--- /dev/null
+++ b/includes/ingress-tls.md
@@ -0,0 +1,64 @@
+```
+cd ..
+```
+
+```
+kn default
+```
+
+```
+mkcert '*.ghost.svc'
+```
+
+```
+k create secret tls ghost-secret --cert=_wildcard.ghost.svc.pem --key=_wildcard.ghost.svc-key.pem
+```
+
+## alternatively, if you can't or you don't want to use mkcert, you can create a selfsigned cert with:
+
+## openssl genrsa -out tls.key 2048
+
+## openssl req -new -x509 -key tls.key -out tls.cert -days 360 -subj /CN=my.ghost.svc
+
+## k create secret tls ghost-secret --cert=tls.cert --key=tls.key
+```
+cat 3-ghost-deployment.yaml
+```
+
+```
+k create -f 3-ghost-deployment.yaml
+```
+
+```
+k expose deployment ghost --port=2368
+```
+
+```
+cat 3-ghost-ingress-tls.yaml
+```
+
+```
+k create -f 3-ghost-ingress-tls.yaml
+```
+
+## Please provide the host entry mapping in your /etc/hosts file like this:
+
+## 192.168.64.23 my.ghost.svc admin.ghost.svc
+
+## the IP should be the IP of the traefik loadbalancer / ingress controller
+
+```
+open https://my.ghost.svc
+```
+
+```
+open https://admin.ghost.svc/ghost
+```
+
+## change the service type to LoadBalancer and access ghost with the loadbalancer IP on port 2368 or on any other node (works on k3s with trafik only), e.g.:
+
+```
+open http://node2:2368
+```
+
+## scale the deployment to have 2 replicas and see how the backend ghost backened https://admin.ghost.svc/ghost doesn't work.
diff --git a/includes/initContainer/0-bare-init.yaml b/includes/initContainer/0-bare-init.yaml
new file mode 100644
index 00000000..670c1cd8
--- /dev/null
+++ b/includes/initContainer/0-bare-init.yaml
@@ -0,0 +1,32 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: bare-inicontainer-pod
+spec:
+ initContainers:
+ - name: first-inicontainer
+ image: bash
+ command: ['sh', '-c', 'echo first-inicontainer: waiting 200 sec && sleep 200']
+ volumeMounts:
+ - name: mypvc
+ mountPath: /workdir
+ - name: second-inicontainer
+ image: bash
+ command: ['sh', '-c', 'echo second-inicontainer: waiting 200 sec && sleep 200']
+ volumeMounts:
+ - name: mypvc
+ mountPath: /workdir
+ containers:
+ - name: application-container
+ image: bash
+ command: ['sh', '-c', 'echo application-container: waiting 200 sec && sleep 200']
+ volumeMounts:
+ - name: mypvc
+ mountPath: /workdir
+ resources:
+ limits:
+ cpu: 200m
+ memory: 200Mi
+ volumes:
+ - name: mypvc
+ emptyDir: {}
\ No newline at end of file
diff --git a/includes/initContainer/0-min-init-container.yaml b/includes/initContainer/0-min-init-container.yaml
new file mode 100644
index 00000000..984510b7
--- /dev/null
+++ b/includes/initContainer/0-min-init-container.yaml
@@ -0,0 +1,7 @@
+initContainers:
+- name: init-firstinicontainer
+ image: bash
+ command: ['sh', '-c', 'sleep 200']
+ volumeMounts:
+ - name: mypvc
+ mountPath: /workdir
\ No newline at end of file
diff --git a/includes/initContainer/1-delaying-application-deployment.yaml b/includes/initContainer/1-delaying-application-deployment.yaml
new file mode 100644
index 00000000..448f9b39
--- /dev/null
+++ b/includes/initContainer/1-delaying-application-deployment.yaml
@@ -0,0 +1,58 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: application-deployment
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: application-deployment
+ template:
+ metadata:
+ labels:
+ app: application-deployment
+ spec:
+ volumes:
+ - name: config-volume
+ configMap:
+ name: app-config
+ initContainers:
+ - name: check-postres-ready
+ image: postgres:12.2-alpine
+ command: ['sh', '-c',
+ 'until pg_isready -h postgres -p 5432;
+ do echo waiting for database; sleep 2; done;']
+ containers:
+ - image: xcoulon/go-url-shortener:0.2.0
+ name: go-url-shortener
+ volumeMounts:
+ - name: config-volume
+ mountPath: /etc/config
+ ports:
+ - containerPort: 8080
+ env:
+ - name: CONFIG_FILE
+ value: /etc/config/config.yaml
+ - name: POSTGRES_HOST
+ value: postgres
+ - name: POSTGRES_PORT
+ value: "5432"
+ - name: POSTGRES_DATABASE
+ valueFrom:
+ secretKeyRef:
+ name: database-secret-config
+ key: dbname
+ - name: POSTGRES_USER
+ valueFrom:
+ secretKeyRef:
+ name: database-secret-config
+ key: username
+ - name: POSTGRES_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: database-secret-config
+ key: password
+ resources:
+ limits:
+ cpu: 200m
+ memory: 400Mi
\ No newline at end of file
diff --git a/includes/initContainer/2-pre-populate-config-pod.yaml b/includes/initContainer/2-pre-populate-config-pod.yaml
new file mode 100644
index 00000000..c9185f7e
--- /dev/null
+++ b/includes/initContainer/2-pre-populate-config-pod.yaml
@@ -0,0 +1,33 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pre-populate-config-pod
+spec:
+ initContainers:
+ - name: config-data
+ image: bash
+ command: ["echo","-n","{'address':'10.0.1.192:5432/db'}", ">","/data/config"]
+ volumeMounts:
+ - name: config-data
+ mountPath: /data
+ resources:
+ limits:
+ cpu: 200m
+ memory: 200Mi
+ containers:
+ - image: bash
+ name: bash-pod
+ args:
+ - bash
+ - -c
+ - 'cat "/data/config" && sleep 3600'
+ volumeMounts:
+ - name: config-data
+ mountPath: /data
+ resources:
+ limits:
+ cpu: 200m
+ memory: 200Mi
+ volumes:
+ - name: config-data
+ emptyDir: {}
\ No newline at end of file
diff --git a/includes/initContainer/3-git-clone-deployment.yaml b/includes/initContainer/3-git-clone-deployment.yaml
new file mode 100644
index 00000000..26ee4d15
--- /dev/null
+++ b/includes/initContainer/3-git-clone-deployment.yaml
@@ -0,0 +1,39 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: git-clone-deployment
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: git-clone-deployment
+ template:
+ metadata:
+ labels:
+ app: git-clone-deployment
+ spec:
+ initContainers:
+ - name: clone-git
+ image: alpine/git:latest
+ command: ['sh', '-c',
+ 'cd /srv && git clone https://github.com/alpine-docker/git.git']
+ volumeMounts:
+ - name: shared-folder
+ mountPath: /srv
+ containers:
+ - image: bash
+ name: bash-pod
+ args:
+ - bash
+ - -c
+ - 'ls -la "/srv/git" && sleep 3600'
+ volumeMounts:
+ - name: shared-folder
+ mountPath: /srv
+ resources:
+ limits:
+ cpu: 200m
+ memory: 200Mi
+ volumes:
+ - name: shared-folder
+ emptyDir: {}
\ No newline at end of file
diff --git a/includes/nginx-pod.yaml b/includes/nginx-pod.yaml
new file mode 100644
index 00000000..393946d9
--- /dev/null
+++ b/includes/nginx-pod.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ labels:
+ run: nginx-pod
+ name: nginx-pod
+spec:
+ containers:
+ - image: nginx
+ name: nginx-pod
diff --git a/includes/openebs-nginx.md b/includes/openebs-nginx.md
new file mode 100644
index 00000000..93b1a20a
--- /dev/null
+++ b/includes/openebs-nginx.md
@@ -0,0 +1,65 @@
+```
+kubectl apply -f addons/openebs/local-hostpath-pvc.yaml
+```
+
+```
+kubectl apply -f addons/openebs/ngix-deployment.yml
+```
+
+```
+kubectl get pvc
+```
+
+```
+##local-hostpath-pvc Bound pvc-55ed95ca-c957-4211-9722-d3b5942a2aca
+```
+
+```
+k get pods -o wide
+```
+
+## nginx-deploy-765579fd89-8d8vv 1/1 Running 0 4m24s 10.42.1.17 node2
+## nginx is running on node2
+```
+multipass shell node2
+```
+
+```
+cd /var/openebs/local/pvc-55ed95ca-c957-4211-9722-d3b5942a2aca/
+```
+
+```
+vi index.html
+```
+
+## paste the following in the index.html file and save:
+
+```
+Hello OpenEBS World on Bonsai Kube
+```
+
+```
+exit
+```
+
+```
+kubectl expose deployment nginx-deploy --port=80 --type=LoadBalancer
+```
+
+```
+kubectl get svc
+```
+
+## get the external ip of the service
+```
+curl http://192.168.64.25
+```
+
+## you should get
+## Hello OpenEBS World on Bonsai Kube
+## or
+
+```
+open http://192.168.64.25
+```
+
diff --git a/includes/service-discovery.md b/includes/service-discovery.md
new file mode 100644
index 00000000..0cd7b9d1
--- /dev/null
+++ b/includes/service-discovery.md
@@ -0,0 +1,78 @@
+```
+cd whereami
+```
+
+```
+k create ns ns1
+```
+
+```
+k create ns ns2
+```
+
+```
+kn ns1
+```
+
+```
+cat kubia-deployment.yaml
+```
+
+```
+k create -f kubia-deployment.yaml
+```
+
+```
+k create -f kubia-deployment.yaml -n ns2
+```
+
+```
+k expose deployment kubia
+```
+
+```
+k get svc
+```
+
+```
+k expose deployment kubia -n ns2
+```
+
+```
+k get svc -n ns2
+```
+
+```
+k exec -it kubia- -- curl kubia.ns2.svc.cluster.local:8080
+```
+
+```
+k scale deployment kubia -n ns2 --replicas 3
+```
+
+## repeat the service call many times and see how loadbalancing works
+
+```
+k exec -it kubia- -- curl kubia.ns2.svc.cluster.local:8080
+```
+
+```
+k exec -n ns2 -it kubia- -- curl kubia.ns1.svc.cluster.local:8080
+```
+
+```
+k exec -it kubia- -- ping kubia.ns2.svc.cluster.local
+```
+
+```
+--> PING kubia.ns2.svc.cluster.local (10.43.109.89) 56(84) bytes of data.
+```
+
+## you don't get any pong, why?
+
+## ssh into a node and examine the IPtable rules
+
+```
+sudo iptables-save | grep kubia
+```
+
diff --git a/includes/test-ns.yaml b/includes/test-ns.yaml
new file mode 100644
index 00000000..7c265c01
--- /dev/null
+++ b/includes/test-ns.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: test
diff --git a/includes/whoami-whoareyou-whereami-problems.md b/includes/whoami-whoareyou-whereami-problems.md
new file mode 100644
index 00000000..a8213330
--- /dev/null
+++ b/includes/whoami-whoareyou-whereami-problems.md
@@ -0,0 +1,89 @@
+```
+k apply -f 1-whoami-deployment.yaml
+```
+
+```
+k get all
+```
+
+## we expose the deployment with a service of type ClusterIP
+
+```
+k create -f 1-whoami-service-ClusterIP.yaml
+```
+
+```
+k get svc
+```
+
+```
+k port-forward service/whoami-service 8080:80
+```
+
+## in a new terminal session call
+```
+curl 127.0.0.1:8080
+```
+
+```
+k delete svc whoami-service
+```
+
+## create a service of type NodePort
+```
+k create -f 1-whoami-service-nodeport.yaml
+```
+
+```
+k get svc
+```
+
+```
+curl csky08:30056 # adapt the nodeport for your env. please !
+```
+
+```
+curl csky09:30056
+```
+
+```
+curl csky10:30056
+```
+
+```
+k delete svc whoami-service-nodeport
+```
+
+```
+k create -f 1-whoami-service-loadbalancer.yaml
+```
+
+```
+k get svc
+```
+
+```
+curl # the external-ip is given from the LB IP pool above
+```
+
+```
+k create -f 2-whoareyou-all.yml
+```
+
+```
+k get all
+```
+
+```
+k get svc
+```
+
+```
+k get ing
+```
+
+```
+curl
+```
+
+## are you happy? 😊
diff --git a/init-containers/README.md b/init-containers/README.md
new file mode 100644
index 00000000..12e0c363
--- /dev/null
+++ b/init-containers/README.md
@@ -0,0 +1,369 @@
+Table of Contents
+=================
+
+- [Table of Contents](#table-of-contents)
+- [Init Containers](#init-containers)
+ - [Understanding init containers](#understanding-init-containers)
+ - [Init containers in use](#init-containers-in-use)
+ - [Pod restart reasons](#pod-restart-reasons)
+- [Debug Init Containers](#debug-init-containers)
+ - [Checking the status of Init Containers](#checking-the-status-of-init-containers)
+ - [Getting details about Init Containers](#getting-details-about-init-containers)
+ - [Accessing logs from Init Containers](#accessing-logs-from-init-containers)
+ - [Understanding Pod status](#understanding-pod-status)
+
+
+# Init Containers
+
+An overview of init containers: specialized containers that run before app containers in a Pod.
+
+Init containers can contain utilities or setup scripts not present in an app image.
+
+You can specify init containers in the Pod specification alongside the `containers` array (which describes app containers).
+
+## Understanding init containers
+
+A Pod can have multiple containers running apps within it, but it can also have one or more init containers, which are run before the app containers are started.
+
+Init containers are exactly like regular containers, except:
+
+- Init containers always run to completion.
+
+- Each init container must complete successfully before the next one starts.
+
+If a Pod's init container fails, the kubelet repeatedly restarts that init container until it succeeds.
+
+However, if the Pod has a `restartPolicy` of Never, and an init container fails during startup of that Pod, Kubernetes treats the overall Pod as failed.
+
+
+#### Init containers in use
+
+This example defines a simple Pod that has two init containers.
+
+The first waits for `myservice`, and the second waits for `mydb`.
+
+Once both init containers complete, the Pod runs the app container from its `spec` section.
+
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+ name: myapp-pod
+ labels:
+ app.kubernetes.io/name: MyApp
+spec:
+ containers:
+ - name: myapp-container
+ image: busybox:1.28
+ command: ['sh', '-c', 'echo The app is running! && sleep 3600']
+ initContainers:
+ - name: init-myservice
+ image: busybox:1.28
+ command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
+ - name: init-mydb
+ image: busybox:1.28
+ command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
+```
+
+You can start this Pod by running:
+
+```shell
+kubectl apply -f myapp.yaml
+```
+
+The output is similar to this:
+
+```
+pod/myapp-pod created
+```
+
+And check on its status with:
+
+```shell
+kubectl get -f myapp.yaml
+```
+
+The output is similar to this:
+
+```
+NAME READY STATUS RESTARTS AGE
+myapp-pod 0/1 Init:0/2 0 6m
+```
+
+or for more details:
+
+```shell
+kubectl describe -f myapp.yaml
+```
+
+The output is similar to this:
+
+```
+Name: myapp-pod
+Namespace: default
+Priority: 0
+Node: rke2-training-node3/84.200.100.249
+Start Time: Tue, 04 Oct 2022 15:57:02 +0530
+Labels: app.kubernetes.io/name=MyApp
+Annotations: cni.projectcalico.org/containerID: 6a0f698417e23f6852018d132aa4a1678fa4831985724c2132d58ddb67169dab
+ cni.projectcalico.org/podIP: 10.42.2.53/32
+ cni.projectcalico.org/podIPs: 10.42.2.53/32
+ kubernetes.io/psp: global-unrestricted-psp
+Status: Pending
+IP: 10.42.2.53
+IPs:
+ IP: 10.42.2.53
+Init Containers:
+ init-myservice:
+ Container ID: containerd://a9ed26b3f20ab875b4b0a17e7865126e284203be06355b4cc35f5c6ec05627a4
+ Image: busybox:1.28
+ Image ID: docker.io/library/busybox@sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
+ Port:
+ Host Port:
+ Command:
+ sh
+ -c
+ until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done
+ State: Running
+ Started: Tue, 04 Oct 2022 15:57:05 +0530
+ Ready: False
+ Restart Count: 0
+ Environment:
+ Mounts:
+ /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-9hxd6 (ro)
+ init-mydb:
+ Container ID:
+ Image: busybox:1.28
+ Image ID:
+ Port:
+ Host Port:
+ Command:
+ sh
+ -c
+ until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done
+ State: Waiting
+ Reason: PodInitializing
+ Ready: False
+ Restart Count: 0
+ Environment:
+ Mounts:
+ /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-9hxd6 (ro)
+Containers:
+ myapp-container:
+ Container ID:
+ Image: busybox:1.28
+ Image ID:
+ Port:
+ Host Port:
+ Command:
+ sh
+ -c
+ echo The app is running! && sleep 3600
+ State: Waiting
+ Reason: PodInitializing
+ Ready: False
+ Restart Count: 0
+ Environment:
+ Mounts:
+ /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-9hxd6 (ro)
+Conditions:
+ Type Status
+ Initialized False
+ Ready False
+ ContainersReady False
+ PodScheduled True
+Volumes:
+ kube-api-access-9hxd6:
+ Type: Projected (a volume that contains injected data from multiple sources)
+ TokenExpirationSeconds: 3607
+ ConfigMapName: kube-root-ca.crt
+ ConfigMapOptional:
+ DownwardAPI: true
+QoS Class: BestEffort
+Node-Selectors:
+Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
+ node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Scheduled 7s default-scheduler Successfully assigned test-ns/myapp-pod to rke2-training-node3
+ Normal Pulling 6s kubelet Pulling image "busybox:1.28"
+ Normal Pulled 4s kubelet Successfully pulled image "busybox:1.28" in 2.713504721s
+ Normal Created 4s kubelet Created container init-myservice
+ Normal Started 4s kubelet Started container init-myservice
+```
+
+To see logs for the init containers in this Pod, run:
+
+```shell
+kubectl logs myapp-pod -c init-myservice # Inspect the first init container
+kubectl logs myapp-pod -c init-mydb # Inspect the second init container
+```
+
+At this point, those init containers will be waiting to discover Services named `mydb` and `myservice`.
+
+Here's a configuration you can use to make those Services appear:
+
+```yaml
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: myservice
+spec:
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 9376
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: mydb
+spec:
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 9377
+```
+
+To create the `mydb` and `myservice` services:
+
+```shell
+kubectl apply -f services.yaml
+```
+
+The output is similar to this:
+
+```
+service/myservice created
+service/mydb created
+```
+
+You'll then see that those init containers complete, and that the `myapp-pod` Pod moves into the Running state:
+
+```shell
+kubectl get -f myapp.yaml
+```
+
+The output is similar to this:
+
+```
+NAME READY STATUS RESTARTS AGE
+myapp-pod 1/1 Running 0 9m
+```
+
+### Pod restart reasons
+
+A Pod can restart, causing re-execution of init containers, for the following reasons:
+
+- The Pod infrastructure container is restarted. This is uncommon and would have to be done by someone with root access to nodes.
+- All containers in a Pod are terminated while `restartPolicy` is set to Always, forcing a restart, and the init container completion record has been lost due to garbage collection.
+
+The Pod will not be restarted when the init container image is changed, or the init container completion record has been lost due to garbage collection. This applies for Kubernetes v1.20 and later.
+
+
+# Debug Init Containers
+
+How to investigate problems related to the execution of Init Containers.
+
+The example command lines below refer to the Pod as `` and the Init Containers as `` and ``.
+
+## Checking the status of Init Containers
+
+Display the status of your pod:
+
+```shell
+kubectl get pod
+```
+
+For example, a status of `Init:1/2` indicates that one of two Init Containers has completed successfully:
+
+```
+NAME READY STATUS RESTARTS AGE
+ 0/1 Init:1/2 0 7s
+```
+
+
+## Getting details about Init Containers
+
+View more detailed information about Init Container execution:
+
+```shell
+kubectl describe pod
+```
+
+For example, a Pod with two Init Containers might show the following:
+
+```
+Init Containers:
+ :
+ Container ID: ...
+ ...
+ State: Terminated
+ Reason: Completed
+ Exit Code: 0
+ Started: ...
+ Finished: ...
+ Ready: True
+ Restart Count: 0
+ ...
+ :
+ Container ID: ...
+ ...
+ State: Waiting
+ Reason: CrashLoopBackOff
+ Last State: Terminated
+ Reason: Error
+ Exit Code: 1
+ Started: ...
+ Finished: ...
+ Ready: False
+ Restart Count: 3
+ ...
+```
+
+You can also access the Init Container statuses programmatically by reading the `status.initContainerStatuses` field on the Pod Spec:
+
+```shell
+kubectl get pod nginx --template '{{.status.initContainerStatuses}}'
+```
+
+Or
+
+You can gather a list of pod names and their pod status condition for programmatic access, which has a type of Initialized with the following JSONPath expression.
+
+```
+kubectl get pods -o=jsonpath='{"Pod Name, Condition Initialized"}{"\n"}{range .items[*]}{.metadata.name},{@.status.conditions[?(@.type=="Initialized")].status}{"\n"}{end}'
+
+```
+
+This command will return the same information as above in raw JSON.
+
+## Accessing logs from Init Containers
+
+Pass the Init Container name along with the Pod name to access its logs.
+
+```shell
+kubectl logs -c
+```
+
+
+## Understanding Pod status
+
+A Pod status beginning with `Init:` summarizes the status of Init Container execution. The table below describes some example status values that you might see while debugging Init Containers.
+
+|Status| Meaning|
+|------|-----------|
+|`Init:N/M`|The Pod has `M` Init Containers, and `N` have completed so far.|
+|`Init:Error`|An Init Container has failed to execute.|
+|`Init:CrashLoopBackOff`|An Init Container has failed repeatedly.|
+|`Pending`|The Pod has not yet begun executing Init Containers.|
+|`PodInitializing` or `Running`|The Pod has already finished executing Init Containers.|
+
+
+
+Reference links:
+- [Kubernetes Documentation/Concepts - Init Containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/)
+- [Kubernetes Documentation/ Debug Init containers](https://kubernetes.io/docs/tasks/debug/debug-application/debug-init-containers/)
+- [Deep Dive Into Kubernetes Init Containers](https://loft.sh/blog/kubernetes-init-containers/)
\ No newline at end of file
diff --git a/init-containers/myapp.yaml b/init-containers/myapp.yaml
new file mode 100644
index 00000000..3da7aa53
--- /dev/null
+++ b/init-containers/myapp.yaml
@@ -0,0 +1,18 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: myapp-pod
+ labels:
+ app.kubernetes.io/name: MyApp
+spec:
+ containers:
+ - name: myapp-container
+ image: busybox:1.28
+ command: ['sh', '-c', 'echo The app is running! && sleep 3600']
+ initContainers:
+ - name: init-myservice
+ image: busybox:1.28
+ command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
+ - name: init-mydb
+ image: busybox:1.28
+ command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
\ No newline at end of file
diff --git a/init-containers/services.yaml b/init-containers/services.yaml
new file mode 100644
index 00000000..60c7d001
--- /dev/null
+++ b/init-containers/services.yaml
@@ -0,0 +1,19 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: myservice
+spec:
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 9376
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: mydb
+spec:
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 9377
\ No newline at end of file
diff --git a/install_helm.sh b/install_helm.sh
new file mode 100755
index 00000000..82b37b39
--- /dev/null
+++ b/install_helm.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+#export KUBECONFIG=k3s.yaml
+kubectl -n kube-system create serviceaccount tiller
+kubectl create clusterrolebinding tiller --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
+curl -LO https://git.io/get_helm.sh
+chmod 700 get_helm.sh
+./get_helm.sh
+helm init --service-account tiller
+kubectl rollout status deployment tiller-deploy -n kube-system
diff --git a/k3d/README.md b/k3d/README.md
new file mode 100644
index 00000000..b3c66eec
--- /dev/null
+++ b/k3d/README.md
@@ -0,0 +1,229 @@
+Table of Contents
+=================
+
+ * [What is k3d?](#what-is-k3d)
+ * [Requirements](#requirements)
+ * [ Install Script](#install-script)
+ * [Install current latest release](#install-current-latest-release)
+ * [Install specific release](#install-specific-release)
+ * [Creating single-node clusters:](#creating-single-node-clusters)
+ * [Creating additional clusters](#creating-additional-clusters)
+ * [Deleting clusters](#deleting-clusters)
+ * [Creating clusters through configs](#creating-clusters-through-configs)
+ * [Open http://localhost in a browser.](#open-httplocalhost-in-a-browser)
+ * [Deleting clusters](#deleting-clusters-1)
+ * [Speed test against kind](#speed-test-against-kind)
+ * [Please go through kind module if you are not already familiar with kind](#please-go-through-kind-module-if-you-are-not-already-familiar-with-kind)
+* [Reference link:](#reference-link)
+
+
+## What is k3d?
+
+k3d is a lightweight wrapper to run [k3s](https://github.com/rancher/k3s) (Rancher Lab’s minimal Kubernetes distribution) in docker.
+
+k3d makes it very easy to create single- and multi-node [k3s](https://github.com/rancher/k3s) clusters in docker, e.g. for local development on Kubernetes.
+
+## Requirements
+
+- [**docker**](https://docs.docker.com/install/) to be able to use k3d at all
+ - Note: k3d v5.x.x requires at least Docker v20.10.5 (runc >= v1.0.0-rc93) to work properly.
+- [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) to interact with the Kubernetes cluster
+
+
+### Install Script
+
+#### Install current latest release
+
+- wget:
+
+```
+wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
+```
+
+- curl:
+
+```
+curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
+```
+
+
+#### Install specific release
+
+Use the install script to grab a specific release (via `TAG` environment variable):
+
+- wget:
+
+```
+wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | TAG=v5.0.0 bash
+```
+
+- curl:
+
+ ```
+curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | TAG=v5.0.0 bash
+```
+
+
+## Creating single-node clusters:
+
+Here, we are creating `cluster-1`:
+
+```
+k3d cluster create cluster-1
+```
+
+Here, we can see the cluster running as container:
+
+```
+docker container ls
+```
+
+k3s is the cluster running as container and the proxy container which will proxy the requests entering into docker and going into that cluster.
+
+Here, list out the pods:
+
+```
+kubectl get pods -A
+```
+
+Here, list out the nodes:
+
+```
+kubectl get nodes
+```
+
+## Creating additional clusters
+
+Here, we are specifying an image (kubernetes version) to create `cluster-2`.
+
+```
+k3d cluster create cluster-2 --image rancher/k3s:v1.20.4-k3s1
+```
+
+Here, we can see the cluster running as container:
+
+```
+docker container ls
+```
+
+
+## Deleting clusters
+Here is the way to delete the cluster:
+
+```
+k3d cluster delete cluster-1
+```
+
+```
+k3d cluster delete cluster-2
+```
+
+
+## Creating clusters through configs
+
+Clone the repository:
+
+```
+git clone https://github.com/vfarcic/k3d-demo.git
+```
+
+```
+cd k3d-demo
+```
+
+Here, we can see the config file and review it:
+
+```
+cat k3d.yaml
+```
+
+ Please note [kind](https://k3d.io/v5.4.6/usage/configfile/#required-fields) to define the kind of config file that you want to use (currently k3d only have the `Simple` config)
+
+```yaml
+kind: Simple #simple type of cluster
+
+apiVersion: k3d.io/v1alpha2
+
+name: my-cluster
+
+image: rancher/k3s:v1.20.4-k3s1 #version of kubernetes we want to run in this cluster
+
+servers: 3 #controlplane
+
+agents: 3 #workernode
+
+ports:
+
+- port: 80:80
+
+ nodeFilters:
+
+ - loadbalancer
+
+# options:
+
+# k3s:
+
+# extraServerArgs:
+
+# - --no-deploy=traefik
+```
+
+Here, we will create the cluster using config file:
+
+```
+k3d cluster create --config k3d.yaml
+```
+
+Here, list out the nodes:
+
+```
+kubectl get nodes
+```
+
+Here, we apply the definition files:
+
+```
+kubectl apply --filename k8s/
+```
+
+#### Open http://localhost in a browser.
+
+
+## Deleting clusters #
+
+```
+k3d cluster delete my-cluster
+```
+
+## Speed test against kind
+
+```
+docker system prune -a -f --volumes
+```
+
+```
+k3d cluster create my-cluster
+```
+
+```
+k3d cluster delete my-cluster
+```
+
+### Please go through kind module if you are not already familiar with kind
+
+```
+kind create cluster --name my-cluster
+```
+
+```
+kind delete cluster --name my-cluster
+```
+
+
+
+# Reference link:
+
+- [K3d - How to run Kubernetes cluster locally using Rancher K3s](https://www.youtube.com/watch?v=mCesuGk-Fks)
+- [gist](https://gist.github.com/vfarcic/b025359ef5ba33353476bbfe881ec5c3)
+- [k3d Installation](https://k3d.io/v5.4.6/)
\ No newline at end of file
diff --git a/k3d/k3d-demo/k3d.yaml b/k3d/k3d-demo/k3d.yaml
new file mode 100644
index 00000000..7824d42d
--- /dev/null
+++ b/k3d/k3d-demo/k3d.yaml
@@ -0,0 +1,14 @@
+kind: Simple
+apiVersion: k3d.io/v1alpha2
+name: my-cluster
+image: rancher/k3s:v1.20.4-k3s1
+servers: 3
+agents: 3
+ports:
+- port: 80:80
+ nodeFilters:
+ - loadbalancer
+# options:
+# k3s:
+# extraServerArgs:
+# - --no-deploy=traefik
diff --git a/k3d/k3d-demo/k8s/deployment.yaml b/k3d/k3d-demo/k8s/deployment.yaml
new file mode 100644
index 00000000..6ec195e0
--- /dev/null
+++ b/k3d/k3d-demo/k8s/deployment.yaml
@@ -0,0 +1,36 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: devops-toolkit
+ labels:
+ app: devops-toolkit
+spec:
+ selector:
+ matchLabels:
+ app: devops-toolkit
+ template:
+ metadata:
+ labels:
+ app: devops-toolkit
+ spec:
+ containers:
+ - name: devops-toolkit
+ image: vfarcic/devops-toolkit-series
+ ports:
+ - containerPort: 80
+ livenessProbe:
+ httpGet:
+ path: /
+ port: 80
+ readinessProbe:
+ httpGet:
+ path: /
+ port: 80
+ resources:
+ limits:
+ cpu: 100m
+ memory: 256Mi
+ requests:
+ cpu: 80m
+ memory: 128Mi
+
diff --git a/k3d/k3d-demo/k8s/ingress.yaml b/k3d/k3d-demo/k8s/ingress.yaml
new file mode 100644
index 00000000..f22f9b86
--- /dev/null
+++ b/k3d/k3d-demo/k8s/ingress.yaml
@@ -0,0 +1,17 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: devops-toolkit
+ annotations:
+ ingress.kubernetes.io/ssl-redirect: "false"
+spec:
+ rules:
+ - http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: devops-toolkit
+ port:
+ number: 80
diff --git a/k3d/k3d-demo/k8s/service.yaml b/k3d/k3d-demo/k8s/service.yaml
new file mode 100644
index 00000000..fd4b4f9c
--- /dev/null
+++ b/k3d/k3d-demo/k8s/service.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: devops-toolkit
+ labels:
+ app: devops-toolkit
+spec:
+ type: ClusterIP
+ ports:
+ - port: 80
+ targetPort: 80
+ protocol: TCP
+ name: http
+ selector:
+ app: devops-toolkit
diff --git a/k3d/k3d-demo/kind.yaml b/k3d/k3d-demo/kind.yaml
new file mode 100644
index 00000000..5fd847d2
--- /dev/null
+++ b/k3d/k3d-demo/kind.yaml
@@ -0,0 +1,22 @@
+kind: Cluster
+apiVersion: kind.x-k8s.io/v1alpha4
+nodes:
+- role: control-plane
+ kubeadmConfigPatches:
+ - |
+ kind: InitConfiguration
+ nodeRegistration:
+ kubeletExtraArgs:
+ node-labels: "ingress-ready=true"
+ extraPortMappings:
+ - containerPort: 80
+ hostPort: 80
+ protocol: TCP
+ - containerPort: 443
+ hostPort: 443
+ protocol: TCP
+- role: control-plane
+- role: control-plane
+- role: worker
+- role: worker
+- role: worker
diff --git a/kind/README.md b/kind/README.md
new file mode 100644
index 00000000..813a754b
--- /dev/null
+++ b/kind/README.md
@@ -0,0 +1,217 @@
+Table of Contents
+=================
+
+- [Table of Contents](#table-of-contents)
+- [Kind](#kind)
+ - [Prerequisites:](#prerequisites)
+ - [Installing With A Package Manager](#installing-with-a-package-manager)
+ - [Installing From Release Binaries](#installing-from-release-binaries)
+ - [Creating a Cluster](#creating-a-cluster)
+ - [Interacting With Your Cluster](#interacting-with-your-cluster)
+ - [Deleting a Cluster](#deleting-a-cluster)
+- [Summary](#summary)
+- [Reference link:](#reference-link)
+
+
+# Kind
+
+kind is a tool for running local Kubernetes clusters using Docker container “nodes”.
+kind was primarily designed for testing Kubernetes itself, but may be used for local development or CI.
+
+## Prerequisites:
+
+- Install Docker Desktop if you are on macOS or Windows OS, or Docker if Linux OS
+
+- If you are on Windows/macOS disable kubernetes from docker desktop if you are using it! As we are using the kind and we need to avoid the duplication.
+
+
+
+### Installing With A Package Manager
+
+The kind community has enabled installation via the following package managers.
+
+On macOS via Homebrew:
+
+```bash
+brew install kind
+```
+
+On macOS via MacPorts:
+
+```bash
+sudo port selfupdate && sudo port install kind
+```
+
+On Windows via Chocolatey
+
+```powershell
+choco install kind
+```
+
+### Installing From Release Binaries
+
+Pre-built binaries are available on our [releases page](https://github.com/kubernetes-sigs/kind/releases).
+
+To install, download the binary for your platform from “Assets”, then rename it to `kind` (or perhaps `kind.exe` on Windows) and place this into your `$PATH` at your preferred binary installation directory.
+
+On Linux:
+
+```bash
+curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.16.0/kind-linux-amd64
+chmod +x ./kind
+sudo mv ./kind /usr/local/bin/kind
+```
+
+On macOS:
+
+```bash
+# for Intel Macs
+[ $(uname -m) = x86_64 ]&& curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.16.0/kind-darwin-amd64
+# for M1 / ARM Macs
+[ $(uname -m) = arm64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.16.0/kind-darwin-arm64
+chmod +x ./kind
+mv ./kind /some-dir-in-your-PATH/kind
+```
+
+On Windows in [PowerShell](https://en.wikipedia.org/wiki/PowerShell):
+
+```powershell
+curl.exe -Lo kind-windows-amd64.exe https://kind.sigs.k8s.io/dl/v0.16.0/kind-windows-amd64
+Move-Item .\kind-windows-amd64.exe c:\some-dir-in-your-PATH\kind.exe
+```
+
+## Creating a Cluster
+
+Creating a Kubernetes cluster is as simple as
+
+```
+kind create cluster --name cluster-1
+kubectl cluster-info --context kind-cluster-1
+kubectl get nodes
+```
+
+Next, run below command which will show us the node as container:
+
+```
+docker container ls
+```
+
+Next, below command will show us the control plane node:
+
+```
+kubectl get nodes
+```
+
+## Interacting With Your Cluster
+
+By default, the cluster access configuration is stored in ${HOME}/.kube/config if $KUBECONFIG environment variable is not set.
+
+Let's create another cluster:
+
+```
+kind create --name cluster-2
+```
+
+When you list your kind clusters, you will see something like the following:
+
+```
+kind get clusters
+
+cluster-1
+cluster-2
+```
+
+
+## Deleting a Cluster
+
+If you created a cluster with `kind create cluster` then deleting is equally simple:
+
+```
+kind delete cluster
+```
+
+If the flag `--name` is not specified, kind will use the default cluster context name `kind` and delete that cluster.
+
+```
+kind delete cluster-1
+```
+
+```
+kind delete cluster-2
+```
+
+A config file with six nodes that enables the clusters with ingress.
+
+```
+git clone https://github.com/vfarcic/kind-demo.git
+```
+
+```
+cd kind-demo
+```
+
+```
+cat multi-node.yaml
+```
+
+```
+kind create cluster --config multi-node.yaml
+```
+
+We will see there are three control-plane nodes and three worker nodes.
+
+```
+kubectl get nodes
+```
+
+
+Next, run below command which will show us the node as container:
+
+```
+docker container ls
+```
+
+You will see total seven containers; one container is used for forwarding request between docker desktop and kind to offer ingress. The other are control-plane and worker nodes.
+
+The k8s folder contains the deployment, ingress and service yaml files:
+
+```
+kubectl apply --filename k8s/
+```
+
+Go to Google chrome:
+
+```
+http://localhost
+```
+
+We won't be able to see the page as nginx-ingress is not installed out of the box with kind.
+
+We can install it by running following command:
+
+```
+kubectl apply --filename ingress-nginx-deploy.yaml
+```
+
+Go to Google chrome:
+
+```
+http://localhost
+```
+
+# Summary
+kind creates kubernetes clusters as containers.
+
+kind is creating control-plane node and worker node as containers.
+
+For Linux users, use kind or Docker Desktop.
+
+For Windows and MacOS users, Docker Desktop (Kubernetes built-in) option is available unless you want to run multi-node cluster and multiple clusters.
+
+# Reference link:
+
+- [Kind Installation](https://kind.sigs.k8s.io/docs/user/quick-start/#installation)
+
+- [How to run local multi-node Kubernetes clusters using kind](https://www.youtube.com/watch?v=C0v5gJSWuSo)
+
+- [multi-node.yaml](https://github.com/vfarcic/kind-demo/blob/master/multi-node.yaml)
\ No newline at end of file
diff --git a/kind/ingress-nginx-deploy.yaml b/kind/ingress-nginx-deploy.yaml
new file mode 100644
index 00000000..9db84b60
--- /dev/null
+++ b/kind/ingress-nginx-deploy.yaml
@@ -0,0 +1,677 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ labels:
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ name: ingress-nginx
+---
+apiVersion: v1
+automountServiceAccountToken: true
+kind: ServiceAccount
+metadata:
+ labels:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx
+ namespace: ingress-nginx
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ labels:
+ app.kubernetes.io/component: admission-webhook
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-admission
+ namespace: ingress-nginx
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ labels:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx
+ namespace: ingress-nginx
+rules:
+- apiGroups:
+ - ""
+ resources:
+ - namespaces
+ verbs:
+ - get
+- apiGroups:
+ - ""
+ resources:
+ - configmaps
+ - pods
+ - secrets
+ - endpoints
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups:
+ - ""
+ resources:
+ - services
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups:
+ - networking.k8s.io
+ resources:
+ - ingresses
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups:
+ - networking.k8s.io
+ resources:
+ - ingresses/status
+ verbs:
+ - update
+- apiGroups:
+ - networking.k8s.io
+ resources:
+ - ingressclasses
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups:
+ - ""
+ resourceNames:
+ - ingress-controller-leader
+ resources:
+ - configmaps
+ verbs:
+ - get
+ - update
+- apiGroups:
+ - ""
+ resources:
+ - configmaps
+ verbs:
+ - create
+- apiGroups:
+ - coordination.k8s.io
+ resourceNames:
+ - ingress-controller-leader
+ resources:
+ - leases
+ verbs:
+ - get
+ - update
+- apiGroups:
+ - coordination.k8s.io
+ resources:
+ - leases
+ verbs:
+ - create
+- apiGroups:
+ - ""
+ resources:
+ - events
+ verbs:
+ - create
+ - patch
+- apiGroups:
+ - discovery.k8s.io
+ resources:
+ - endpointslices
+ verbs:
+ - list
+ - watch
+ - get
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ labels:
+ app.kubernetes.io/component: admission-webhook
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-admission
+ namespace: ingress-nginx
+rules:
+- apiGroups:
+ - ""
+ resources:
+ - secrets
+ verbs:
+ - get
+ - create
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ labels:
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx
+rules:
+- apiGroups:
+ - ""
+ resources:
+ - configmaps
+ - endpoints
+ - nodes
+ - pods
+ - secrets
+ - namespaces
+ verbs:
+ - list
+ - watch
+- apiGroups:
+ - coordination.k8s.io
+ resources:
+ - leases
+ verbs:
+ - list
+ - watch
+- apiGroups:
+ - ""
+ resources:
+ - nodes
+ verbs:
+ - get
+- apiGroups:
+ - ""
+ resources:
+ - services
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups:
+ - networking.k8s.io
+ resources:
+ - ingresses
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups:
+ - ""
+ resources:
+ - events
+ verbs:
+ - create
+ - patch
+- apiGroups:
+ - networking.k8s.io
+ resources:
+ - ingresses/status
+ verbs:
+ - update
+- apiGroups:
+ - networking.k8s.io
+ resources:
+ - ingressclasses
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups:
+ - discovery.k8s.io
+ resources:
+ - endpointslices
+ verbs:
+ - list
+ - watch
+ - get
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ labels:
+ app.kubernetes.io/component: admission-webhook
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-admission
+rules:
+- apiGroups:
+ - admissionregistration.k8s.io
+ resources:
+ - validatingwebhookconfigurations
+ verbs:
+ - get
+ - update
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ labels:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx
+ namespace: ingress-nginx
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: ingress-nginx
+subjects:
+- kind: ServiceAccount
+ name: ingress-nginx
+ namespace: ingress-nginx
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ labels:
+ app.kubernetes.io/component: admission-webhook
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-admission
+ namespace: ingress-nginx
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: ingress-nginx-admission
+subjects:
+- kind: ServiceAccount
+ name: ingress-nginx-admission
+ namespace: ingress-nginx
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ labels:
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: ingress-nginx
+subjects:
+- kind: ServiceAccount
+ name: ingress-nginx
+ namespace: ingress-nginx
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ labels:
+ app.kubernetes.io/component: admission-webhook
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-admission
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: ingress-nginx-admission
+subjects:
+- kind: ServiceAccount
+ name: ingress-nginx-admission
+ namespace: ingress-nginx
+---
+apiVersion: v1
+data:
+ allow-snippet-annotations: "true"
+kind: ConfigMap
+metadata:
+ labels:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-controller
+ namespace: ingress-nginx
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-controller
+ namespace: ingress-nginx
+spec:
+ ipFamilies:
+ - IPv4
+ ipFamilyPolicy: SingleStack
+ ports:
+ - appProtocol: http
+ name: http
+ port: 80
+ protocol: TCP
+ targetPort: http
+ - appProtocol: https
+ name: https
+ port: 443
+ protocol: TCP
+ targetPort: https
+ selector:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ type: NodePort
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-controller-admission
+ namespace: ingress-nginx
+spec:
+ ports:
+ - appProtocol: https
+ name: https-webhook
+ port: 443
+ targetPort: webhook
+ selector:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ type: ClusterIP
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-controller
+ namespace: ingress-nginx
+spec:
+ minReadySeconds: 0
+ revisionHistoryLimit: 10
+ selector:
+ matchLabels:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ strategy:
+ rollingUpdate:
+ maxUnavailable: 1
+ type: RollingUpdate
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ spec:
+ containers:
+ - args:
+ - /nginx-ingress-controller
+ - --election-id=ingress-controller-leader
+ - --controller-class=k8s.io/ingress-nginx
+ - --ingress-class=nginx
+ - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
+ - --validating-webhook=:8443
+ - --validating-webhook-certificate=/usr/local/certificates/cert
+ - --validating-webhook-key=/usr/local/certificates/key
+ - --watch-ingress-without-class=true
+ - --publish-status-address=localhost
+ env:
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ - name: POD_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ - name: LD_PRELOAD
+ value: /usr/local/lib/libmimalloc.so
+ image: registry.k8s.io/ingress-nginx/controller:v1.4.0@sha256:34ee929b111ffc7aa426ffd409af44da48e5a0eea1eb2207994d9e0c0882d143
+ imagePullPolicy: IfNotPresent
+ lifecycle:
+ preStop:
+ exec:
+ command:
+ - /wait-shutdown
+ livenessProbe:
+ failureThreshold: 5
+ httpGet:
+ path: /healthz
+ port: 10254
+ scheme: HTTP
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ successThreshold: 1
+ timeoutSeconds: 1
+ name: controller
+ ports:
+ - containerPort: 80
+ hostPort: 80
+ name: http
+ protocol: TCP
+ - containerPort: 443
+ hostPort: 443
+ name: https
+ protocol: TCP
+ - containerPort: 8443
+ name: webhook
+ protocol: TCP
+ readinessProbe:
+ failureThreshold: 3
+ httpGet:
+ path: /healthz
+ port: 10254
+ scheme: HTTP
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ successThreshold: 1
+ timeoutSeconds: 1
+ resources:
+ requests:
+ cpu: 100m
+ memory: 90Mi
+ securityContext:
+ allowPrivilegeEscalation: true
+ capabilities:
+ add:
+ - NET_BIND_SERVICE
+ drop:
+ - ALL
+ runAsUser: 101
+ volumeMounts:
+ - mountPath: /usr/local/certificates/
+ name: webhook-cert
+ readOnly: true
+ dnsPolicy: ClusterFirst
+ nodeSelector:
+ ingress-ready: "true"
+ kubernetes.io/os: linux
+ serviceAccountName: ingress-nginx
+ terminationGracePeriodSeconds: 0
+ tolerations:
+ - effect: NoSchedule
+ key: node-role.kubernetes.io/master
+ operator: Equal
+ - effect: NoSchedule
+ key: node-role.kubernetes.io/control-plane
+ operator: Equal
+ volumes:
+ - name: webhook-cert
+ secret:
+ secretName: ingress-nginx-admission
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+ labels:
+ app.kubernetes.io/component: admission-webhook
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-admission-create
+ namespace: ingress-nginx
+spec:
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/component: admission-webhook
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-admission-create
+ spec:
+ containers:
+ - args:
+ - create
+ - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
+ - --namespace=$(POD_NAMESPACE)
+ - --secret-name=ingress-nginx-admission
+ env:
+ - name: POD_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20220916-gd32f8c343@sha256:39c5b2e3310dc4264d638ad28d9d1d96c4cbb2b2dcfb52368fe4e3c63f61e10f
+ imagePullPolicy: IfNotPresent
+ name: create
+ securityContext:
+ allowPrivilegeEscalation: false
+ nodeSelector:
+ kubernetes.io/os: linux
+ restartPolicy: OnFailure
+ securityContext:
+ fsGroup: 2000
+ runAsNonRoot: true
+ runAsUser: 2000
+ serviceAccountName: ingress-nginx-admission
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+ labels:
+ app.kubernetes.io/component: admission-webhook
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-admission-patch
+ namespace: ingress-nginx
+spec:
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/component: admission-webhook
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-admission-patch
+ spec:
+ containers:
+ - args:
+ - patch
+ - --webhook-name=ingress-nginx-admission
+ - --namespace=$(POD_NAMESPACE)
+ - --patch-mutating=false
+ - --secret-name=ingress-nginx-admission
+ - --patch-failure-policy=Fail
+ env:
+ - name: POD_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ image: registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20220916-gd32f8c343@sha256:39c5b2e3310dc4264d638ad28d9d1d96c4cbb2b2dcfb52368fe4e3c63f61e10f
+ imagePullPolicy: IfNotPresent
+ name: patch
+ securityContext:
+ allowPrivilegeEscalation: false
+ nodeSelector:
+ kubernetes.io/os: linux
+ restartPolicy: OnFailure
+ securityContext:
+ fsGroup: 2000
+ runAsNonRoot: true
+ runAsUser: 2000
+ serviceAccountName: ingress-nginx-admission
+---
+apiVersion: networking.k8s.io/v1
+kind: IngressClass
+metadata:
+ labels:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: nginx
+spec:
+ controller: k8s.io/ingress-nginx
+---
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+ labels:
+ app.kubernetes.io/component: admission-webhook
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ app.kubernetes.io/part-of: ingress-nginx
+ app.kubernetes.io/version: 1.4.0
+ name: ingress-nginx-admission
+webhooks:
+- admissionReviewVersions:
+ - v1
+ clientConfig:
+ service:
+ name: ingress-nginx-controller-admission
+ namespace: ingress-nginx
+ path: /networking/v1/ingresses
+ failurePolicy: Fail
+ matchPolicy: Equivalent
+ name: validate.nginx.ingress.kubernetes.io
+ rules:
+ - apiGroups:
+ - networking.k8s.io
+ apiVersions:
+ - v1
+ operations:
+ - CREATE
+ - UPDATE
+ resources:
+ - ingresses
+ sideEffects: None
+
+
+ #https://github.com/kubernetes/ingress-nginx/blob/main/deploy/static/provider/kind/deploy.yaml
+
+ #https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
\ No newline at end of file
diff --git a/kind/kind-demo/k8s/deployment.yaml b/kind/kind-demo/k8s/deployment.yaml
new file mode 100644
index 00000000..6ec195e0
--- /dev/null
+++ b/kind/kind-demo/k8s/deployment.yaml
@@ -0,0 +1,36 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: devops-toolkit
+ labels:
+ app: devops-toolkit
+spec:
+ selector:
+ matchLabels:
+ app: devops-toolkit
+ template:
+ metadata:
+ labels:
+ app: devops-toolkit
+ spec:
+ containers:
+ - name: devops-toolkit
+ image: vfarcic/devops-toolkit-series
+ ports:
+ - containerPort: 80
+ livenessProbe:
+ httpGet:
+ path: /
+ port: 80
+ readinessProbe:
+ httpGet:
+ path: /
+ port: 80
+ resources:
+ limits:
+ cpu: 100m
+ memory: 256Mi
+ requests:
+ cpu: 80m
+ memory: 128Mi
+
diff --git a/kind/kind-demo/k8s/ingress.yaml b/kind/kind-demo/k8s/ingress.yaml
new file mode 100644
index 00000000..4c0ee789
--- /dev/null
+++ b/kind/kind-demo/k8s/ingress.yaml
@@ -0,0 +1,21 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: devops-toolkit
+ annotations:
+ ingress.kubernetes.io/ssl-redirect: "false"
+ nginx.ingress.kubernetes.io/ssl-redirect: "false"
+ ingress.kubernetes.io/rewrite-target: /
+ nginx.ingress.kubernetes.io/rewrite-target: /
+spec:
+ rules:
+ - http:
+ paths:
+ - path: /
+ pathType: ImplementationSpecific
+ backend:
+ service:
+ name: devops-toolkit
+ port:
+ number: 80
+ # host: dev.devops-toolkit.192.168.64.199.xip.io
diff --git a/kind/kind-demo/k8s/service.yaml b/kind/kind-demo/k8s/service.yaml
new file mode 100644
index 00000000..fd4b4f9c
--- /dev/null
+++ b/kind/kind-demo/k8s/service.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: devops-toolkit
+ labels:
+ app: devops-toolkit
+spec:
+ type: ClusterIP
+ ports:
+ - port: 80
+ targetPort: 80
+ protocol: TCP
+ name: http
+ selector:
+ app: devops-toolkit
diff --git a/kind/kind-demo/multi-node.yaml b/kind/kind-demo/multi-node.yaml
new file mode 100644
index 00000000..5fd847d2
--- /dev/null
+++ b/kind/kind-demo/multi-node.yaml
@@ -0,0 +1,22 @@
+kind: Cluster
+apiVersion: kind.x-k8s.io/v1alpha4
+nodes:
+- role: control-plane
+ kubeadmConfigPatches:
+ - |
+ kind: InitConfiguration
+ nodeRegistration:
+ kubeletExtraArgs:
+ node-labels: "ingress-ready=true"
+ extraPortMappings:
+ - containerPort: 80
+ hostPort: 80
+ protocol: TCP
+ - containerPort: 443
+ hostPort: 443
+ protocol: TCP
+- role: control-plane
+- role: control-plane
+- role: worker
+- role: worker
+- role: worker
diff --git a/kube-prometheus-stack/.helmignore b/kube-prometheus-stack/.helmignore
new file mode 100644
index 00000000..1937f42c
--- /dev/null
+++ b/kube-prometheus-stack/.helmignore
@@ -0,0 +1,28 @@
+# 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
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+# helm/charts
+OWNERS
+hack/
+ci/
+kube-prometheus-*.tgz
+
+unittests/
diff --git a/kube-prometheus-stack/CONTRIBUTING.md b/kube-prometheus-stack/CONTRIBUTING.md
new file mode 100644
index 00000000..f6ce2a32
--- /dev/null
+++ b/kube-prometheus-stack/CONTRIBUTING.md
@@ -0,0 +1,12 @@
+# Contributing Guidelines
+
+## How to contribute to this chart
+
+1. Fork this repository, develop and test your Chart.
+1. Bump the chart version for every change.
+1. Ensure PR title has the prefix `[kube-prometheus-stack]`
+1. When making changes to rules or dashboards, see the README.md section on how to sync data from upstream repositories
+1. Check the `hack/minikube` folder has scripts to set up minikube and components of this chart that will allow all components to be scraped. You can use this configuration when validating your changes.
+1. Check for changes of RBAC rules.
+1. Check for changes in CRD specs.
+1. PR must pass the linter (`helm lint`)
diff --git a/kube-prometheus-stack/Chart.lock b/kube-prometheus-stack/Chart.lock
new file mode 100644
index 00000000..98ac4683
--- /dev/null
+++ b/kube-prometheus-stack/Chart.lock
@@ -0,0 +1,12 @@
+dependencies:
+- name: kube-state-metrics
+ repository: https://prometheus-community.github.io/helm-charts
+ version: 4.20.2
+- name: prometheus-node-exporter
+ repository: https://prometheus-community.github.io/helm-charts
+ version: 4.3.0
+- name: grafana
+ repository: https://grafana.github.io/helm-charts
+ version: 6.40.0
+digest: sha256:d4d620f64b5e709d0759161f53ef1712c4cc6e77ff239c3653ffca9242723f68
+generated: "2022-09-30T23:57:26.074133+03:00"
diff --git a/kube-prometheus-stack/Chart.yaml b/kube-prometheus-stack/Chart.yaml
new file mode 100644
index 00000000..a0a918d7
--- /dev/null
+++ b/kube-prometheus-stack/Chart.yaml
@@ -0,0 +1,54 @@
+annotations:
+ artifacthub.io/links: |
+ - name: Chart Source
+ url: https://github.com/prometheus-community/helm-charts
+ - name: Upstream Project
+ url: https://github.com/prometheus-operator/kube-prometheus
+ artifacthub.io/operator: "true"
+apiVersion: v2
+appVersion: 0.59.2
+dependencies:
+- condition: kubeStateMetrics.enabled
+ name: kube-state-metrics
+ repository: https://prometheus-community.github.io/helm-charts
+ version: 4.20.*
+- condition: nodeExporter.enabled
+ name: prometheus-node-exporter
+ repository: https://prometheus-community.github.io/helm-charts
+ version: 4.3.*
+- condition: grafana.enabled
+ name: grafana
+ repository: https://grafana.github.io/helm-charts
+ version: 6.40.*
+description: kube-prometheus-stack collects Kubernetes manifests, Grafana dashboards,
+ and Prometheus rules combined with documentation and scripts to provide easy to
+ operate end-to-end Kubernetes cluster monitoring with Prometheus using the Prometheus
+ Operator.
+home: https://github.com/prometheus-operator/kube-prometheus
+icon: https://raw.githubusercontent.com/prometheus/prometheus.github.io/master/assets/prometheus_logo-cb55bb5c346.png
+keywords:
+- operator
+- prometheus
+- kube-prometheus
+kubeVersion: '>=1.16.0-0'
+maintainers:
+- email: andrew@quadcorps.co.uk
+ name: andrewgkew
+- email: cedric@desaintmartin.fr
+ name: desaintmartin
+- email: gianrubio@gmail.com
+ name: gianrubio
+- email: github.gkarthiks@gmail.com
+ name: gkarthiks
+- email: kube-prometheus-stack@sisti.pt
+ name: GMartinez-Sisti
+- email: scott@r6by.com
+ name: scottrigby
+- email: miroslav.hadzhiev@gmail.com
+ name: Xtigyro
+name: kube-prometheus-stack
+sources:
+- https://github.com/prometheus-community/helm-charts
+- https://github.com/prometheus-operator/kube-prometheus
+type: application
+version: 40.3.1
diff --git a/kube-prometheus-stack/Readme.md b/kube-prometheus-stack/Readme.md
new file mode 100644
index 00000000..76bbd07c
--- /dev/null
+++ b/kube-prometheus-stack/Readme.md
@@ -0,0 +1,284 @@
+Table of Contents
+=================
+
+- [Table of Contents](#table-of-contents)
+- [What is Prometheus?](#what-is-prometheus)
+ - [Features](#features)
+ - [Architecture](#architecture)
+- [What is Grafana?](#what-is-grafana)
+ - [Why use Grafana?](#why-use-grafana)
+- [kube-prometheus-stack](#kube-prometheus-stack)
+ - [Prerequisites](#prerequisites)
+ - [Get Helm Repository Info](#get-helm-repository-info)
+ - [Reference links](#reference-links)
+
+
+# What is Prometheus?
+
+Prometheus is an open-source systems monitoring and alerting toolkit.
+
+It collects and stores its metrics as time series data, i.e. metrics information is stored with the timestamp at which it was recorded, alongside optional key-value pairs called labels.
+
+## Features
+
+Prometheus's main features are:
+
+- a multi-dimensional data model with time series data identified by metric name and key/value pairs
+- PromQL, a flexible query language to leverage this dimensionality
+- no reliance on distributed storage; single server nodes are autonomous
+- time series collection happens via a pull model over HTTP
+- pushing time series is supported via an intermediary gateway
+- targets are discovered via service discovery or static configuration
+- multiple modes of graphing and dashboarding support
+
+## Architecture
+
+This diagram illustrates the architecture of Prometheus and some of its ecosystem components:
+
+![prometheus-architecture](/images/prometheus-architecture.png)
+
+# What is Grafana?
+
+Grafana enables you to query, visualize, alert on, and explore your metrics, logs, and traces wherever they are stored.
+
+Grafana provides you with tools to turn your time-series database (TSDB) data into insightful graphs and visualizations.
+
+## Why use Grafana?
+
+- **Unifying the existing data from multiple sources(Kubernetes cluster, different cloud services, etc..) and visualize it from the single dashboard.**
+
+- **Easily accessible and visualization of data.**
+
+- **Insightful dashboard created from the provided data sources.**
+
+- **Translate and transform any of your data into flexible and versatile dashboards.**
+
+- **With advanced querying and transformation capabilities, you can customize your panels to create visualizations that are actually helpful for you.**
+
+# kube-prometheus-stack
+
+A collection of Kubernetes manifests, Grafana dashboards, Alert manager and Prometheus rules, which will allow us to visualize, query, and alert metrics.
+
+## Prerequisites
+
+- Kubernetes 1.16+
+- Helm 3+
+
+To monitor the kubernetes cluster, we are going to need a cluster up and running.
+
+```
+kubectl get nodes
+```
+
+We are going to use the helm package manager to install kube prometheus stack.
+
+## Get Helm Repository Info
+
+Here, we will fetch the `kube-prometheus-stack` packages from a `prometheus-community` repository, and download it locally.
+
+```
+helm pull prometheus-community/kube-prometheus-stack
+```
+
+Please extract `kube-prometheus-stack` and go to the directory.
+
+Here, we will add the chart repository.
+
+```
+helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
+```
+
+The following command will update the local repository with the latest version:
+
+```
+helm repo update
+```
+
+Here, we will create a namespace to avoid installing on default namespace:
+
+```
+kubectl create namespace monitoring
+```
+
+Here, we will verify the namespace that it is created:
+
+```
+kubectl get namespace
+```
+
+For secure password, we will create a secret named `grafana-admin-credentials` and store it in kubernetes and use that secret for grafana dashboard sign-in.
+
+Echo username and password to a file:
+
+```
+echo -n 'adminuser' > ./admin-user # change your username
+```
+
+```
+cat admin-user
+```
+
+```
+echo -n 'p@ssw0rd1!' > ./admin-password # change your password
+```
+
+```
+ cat admin-password
+```
+
+Here, we will create a kubernetes secret:
+
+```
+kubectl create secret generic grafana-admin-credentials --from-file=./admin-user --from-file=admin-password -n monitoring
+```
+
+Output:
+
+```
+secret/grafana-admin-credentials created
+```
+
+We can verify the secret:
+
+```
+kubectl describe secret -n monitoring grafana-admin-credentials
+```
+
+Output:
+
+```
+Name: grafana-admin-credentials
+Namespace: monitoring
+Labels:
+Annotations:
+
+Type: Opaque
+
+Data
+====
+admin-password: 10 bytes
+admin-user: 9 bytes
+```
+
+We can see the `grafana-admin-credentials` json output:
+
+```
+k get secrets grafana-admin-credentials -o json
+```
+
+Output:
+
+```json
+{
+ "apiVersion": "v1",
+ "data": {
+ "admin-password": "cEBzc3cwcmQxIQ==",
+ "admin-user": "YWRtaW51c2Vy"
+ },
+ "kind": "Secret",
+ "metadata": {
+ "creationTimestamp": "2022-10-06T05:18:57Z",
+ "name": "grafana-admin-credentials",
+ "namespace": "monitoring",
+ "resourceVersion": "17245153",
+ "uid": "e0e524ea-5805-4f37-b043-ce33c9cb6286"
+ },
+ "type": "Opaque"
+}
+```
+
+Here, we will decode the `admin-user` property from base64 as the secrets are encoded with base64:
+
+```
+kubectl get secret -n monitoring grafana-admin-credentials -o jsonpath="{.data.admin-user}" | base64 --decode
+````
+
+Output:
+
+```
+adminuser%
+```
+
+Here, we will decode the `admin-password` property from base64
+
+```
+kubectl get secret -n monitoring grafana-admin-credentials -o jsonpath="{.data.admin-password}" | base64 --decode
+```
+
+Output:
+
+```
+p@ssw0rd1!%
+```
+
+Remove username and password file from filesystem:
+
+```
+rm admin-user && rm admin-password
+```
+
+Here, we have provided release name: `prometheus` , repository name: `prometheus-community/kube-prometheus-stack` and we have mentioned `values.yaml` file that we have modified:
+
+Install command:
+
+```
+helm install prometheus -n monitoring prometheus-community/kube-prometheus-stack -f values.yaml
+```
+
+Here, we will list down the resources that have been deployed:
+
+```
+kubectl get deployments
+```
+
+```
+kubectl get pods
+```
+
+```
+kubectl get ds
+```
+
+```
+kubectl get rs
+```
+
+```
+kubectl get sts
+```
+
+```
+kubectl get svc
+```
+
+Here, we are going to port-forward:
+
+```
+kubectl port-forward -n monitoring [grafana-pod-name] 8080:3000
+```
+
+Now, go to your browser:
+
+```
+http://localhost:8080
+```
+
+Enter your grafana username and password.
+
+Now, you will be able to browse through dashboards.
+
+
+## Reference links
+
+- [Prometheus Overview](https://prometheus.io/docs/introduction/overview/)
+
+- [Grafana Overview](https://grafana.com/grafana/)
+
+- [Dashboards with Grafana and Prometheus - Monitoring](https://www.youtube.com/watch?v=fzny5uUaAeY)
+
+- [kube-grafana-prometheus documentation](https://docs.technotim.live/posts/kube-grafana-prometheus/)
+
+- [updated yaml file](https://github.com/techno-tim/launchpad/blob/master/kubernetes/kube-prometheus-stack/values.yml)
+
+
+
diff --git a/kube-prometheus-stack/charts/grafana/.helmignore b/kube-prometheus-stack/charts/grafana/.helmignore
new file mode 100644
index 00000000..8cade131
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/.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
+*~
+# Various IDEs
+.vscode
+.project
+.idea/
+*.tmproj
+OWNERS
diff --git a/kube-prometheus-stack/charts/grafana/Chart.yaml b/kube-prometheus-stack/charts/grafana/Chart.yaml
new file mode 100644
index 00000000..7b597168
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/Chart.yaml
@@ -0,0 +1,22 @@
+apiVersion: v2
+appVersion: 9.1.6
+description: The leading tool for querying and visualizing time series and metrics.
+home: https://grafana.net
+icon: https://raw.githubusercontent.com/grafana/grafana/master/public/img/logo_transparent_400x.png
+kubeVersion: ^1.8.0-0
+maintainers:
+- email: zanhsieh@gmail.com
+ name: zanhsieh
+- email: rluckie@cisco.com
+ name: rtluckie
+- email: maor.friedman@redhat.com
+ name: maorfr
+- email: miroslav.hadzhiev@gmail.com
+ name: Xtigyro
+- email: mail@torstenwalter.de
+ name: torstenwalter
+name: grafana
+sources:
+- https://github.com/grafana/grafana
+type: application
+version: 6.40.0
diff --git a/kube-prometheus-stack/charts/grafana/README.md b/kube-prometheus-stack/charts/grafana/README.md
new file mode 100644
index 00000000..6ec2a96d
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/README.md
@@ -0,0 +1,590 @@
+# Grafana Helm Chart
+
+* Installs the web dashboarding system [Grafana](http://grafana.org/)
+
+## Get Repo Info
+
+```console
+helm repo add grafana https://grafana.github.io/helm-charts
+helm repo update
+```
+
+_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._
+
+## Installing the Chart
+
+To install the chart with the release name `my-release`:
+
+```console
+helm install my-release grafana/grafana
+```
+
+## Uninstalling the Chart
+
+To uninstall/delete the my-release deployment:
+
+```console
+helm delete my-release
+```
+
+The command removes all the Kubernetes components associated with the chart and deletes the release.
+
+## Upgrading an existing Release to a new major version
+
+A major chart version change (like v1.2.3 -> v2.0.0) indicates that there is an
+incompatible breaking change needing manual actions.
+
+### To 4.0.0 (And 3.12.1)
+
+This version requires Helm >= 2.12.0.
+
+### To 5.0.0
+
+You have to add --force to your helm upgrade command as the labels of the chart have changed.
+
+### To 6.0.0
+
+This version requires Helm >= 3.1.0.
+
+## Configuration
+
+| Parameter | Description | Default |
+|-------------------------------------------|-----------------------------------------------|---------------------------------------------------------|
+| `replicas` | Number of nodes | `1` |
+| `podDisruptionBudget.minAvailable` | Pod disruption minimum available | `nil` |
+| `podDisruptionBudget.maxUnavailable` | Pod disruption maximum unavailable | `nil` |
+| `deploymentStrategy` | Deployment strategy | `{ "type": "RollingUpdate" }` |
+| `livenessProbe` | Liveness Probe settings | `{ "httpGet": { "path": "/api/health", "port": 3000 } "initialDelaySeconds": 60, "timeoutSeconds": 30, "failureThreshold": 10 }` |
+| `readinessProbe` | Readiness Probe settings | `{ "httpGet": { "path": "/api/health", "port": 3000 } }`|
+| `securityContext` | Deployment securityContext | `{"runAsUser": 472, "runAsGroup": 472, "fsGroup": 472}` |
+| `priorityClassName` | Name of Priority Class to assign pods | `nil` |
+| `image.repository` | Image repository | `grafana/grafana` |
+| `image.tag` | Overrides the Grafana image tag whose default is the chart appVersion (`Must be >= 5.0.0`) | `` |
+| `image.sha` | Image sha (optional) | `` |
+| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
+| `image.pullSecrets` | Image pull secrets (can be templated) | `[]` |
+| `service.enabled` | Enable grafana service | `true` |
+| `service.type` | Kubernetes service type | `ClusterIP` |
+| `service.port` | Kubernetes port where service is exposed | `80` |
+| `service.portName` | Name of the port on the service | `service` |
+| `service.appProtocol` | Adds the appProtocol field to the service | `` |
+| `service.targetPort` | Internal service is port | `3000` |
+| `service.nodePort` | Kubernetes service nodePort | `nil` |
+| `service.annotations` | Service annotations (can be templated) | `{}` |
+| `service.labels` | Custom labels | `{}` |
+| `service.clusterIP` | internal cluster service IP | `nil` |
+| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `nil` |
+| `service.loadBalancerSourceRanges` | list of IP CIDRs allowed access to lb (if supported) | `[]` |
+| `service.externalIPs` | service external IP addresses | `[]` |
+| `headlessService` | Create a headless service | `false` |
+| `extraExposePorts` | Additional service ports for sidecar containers| `[]` |
+| `hostAliases` | adds rules to the pod's /etc/hosts | `[]` |
+| `ingress.enabled` | Enables Ingress | `false` |
+| `ingress.annotations` | Ingress annotations (values are templated) | `{}` |
+| `ingress.labels` | Custom labels | `{}` |
+| `ingress.path` | Ingress accepted path | `/` |
+| `ingress.pathType` | Ingress type of path | `Prefix` |
+| `ingress.hosts` | Ingress accepted hostnames | `["chart-example.local"]` |
+| `ingress.extraPaths` | Ingress extra paths to prepend to every host configuration. Useful when configuring [custom actions with AWS ALB Ingress Controller](https://kubernetes-sigs.github.io/aws-alb-ingress-controller/guide/ingress/annotation/#actions). Requires `ingress.hosts` to have one or more host entries. | `[]` |
+| `ingress.tls` | Ingress TLS configuration | `[]` |
+| `resources` | CPU/Memory resource requests/limits | `{}` |
+| `nodeSelector` | Node labels for pod assignment | `{}` |
+| `tolerations` | Toleration labels for pod assignment | `[]` |
+| `affinity` | Affinity settings for pod assignment | `{}` |
+| `extraInitContainers` | Init containers to add to the grafana pod | `{}` |
+| `extraContainers` | Sidecar containers to add to the grafana pod | `""` |
+| `extraContainerVolumes` | Volumes that can be mounted in sidecar containers | `[]` |
+| `extraLabels` | Custom labels for all manifests | `{}` |
+| `schedulerName` | Name of the k8s scheduler (other than default) | `nil` |
+| `persistence.enabled` | Use persistent volume to store data | `false` |
+| `persistence.type` | Type of persistence (`pvc` or `statefulset`) | `pvc` |
+| `persistence.size` | Size of persistent volume claim | `10Gi` |
+| `persistence.existingClaim` | Use an existing PVC to persist data (can be templated) | `nil` |
+| `persistence.storageClassName` | Type of persistent volume claim | `nil` |
+| `persistence.accessModes` | Persistence access modes | `[ReadWriteOnce]` |
+| `persistence.annotations` | PersistentVolumeClaim annotations | `{}` |
+| `persistence.finalizers` | PersistentVolumeClaim finalizers | `[ "kubernetes.io/pvc-protection" ]` |
+| `persistence.subPath` | Mount a sub dir of the persistent volume (can be templated) | `nil` |
+| `persistence.inMemory.enabled` | If persistence is not enabled, whether to mount the local storage in-memory to improve performance | `false` |
+| `persistence.inMemory.sizeLimit` | SizeLimit for the in-memory local storage | `nil` |
+| `initChownData.enabled` | If false, don't reset data ownership at startup | true |
+| `initChownData.image.repository` | init-chown-data container image repository | `busybox` |
+| `initChownData.image.tag` | init-chown-data container image tag | `1.31.1` |
+| `initChownData.image.sha` | init-chown-data container image sha (optional)| `""` |
+| `initChownData.image.pullPolicy` | init-chown-data container image pull policy | `IfNotPresent` |
+| `initChownData.resources` | init-chown-data pod resource requests & limits | `{}` |
+| `schedulerName` | Alternate scheduler name | `nil` |
+| `env` | Extra environment variables passed to pods | `{}` |
+| `envValueFrom` | Environment variables from alternate sources. See the API docs on [EnvVarSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#envvarsource-v1-core) for format details. Can be templated | `{}` |
+| `envFromSecret` | Name of a Kubernetes secret (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `""` |
+| `envFromSecrets` | List of Kubernetes secrets (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `[]` |
+| `envFromConfigMaps` | List of Kubernetes ConfigMaps (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `[]` |
+| `envRenderSecret` | Sensible environment variables passed to pods and stored as secret | `{}` |
+| `enableServiceLinks` | Inject Kubernetes services as environment variables. | `true` |
+| `extraSecretMounts` | Additional grafana server secret mounts | `[]` |
+| `extraVolumeMounts` | Additional grafana server volume mounts | `[]` |
+| `createConfigmap` | Enable creating the grafana configmap | `true` |
+| `extraConfigmapMounts` | Additional grafana server configMap volume mounts (values are templated) | `[]` |
+| `extraEmptyDirMounts` | Additional grafana server emptyDir volume mounts | `[]` |
+| `plugins` | Plugins to be loaded along with Grafana | `[]` |
+| `datasources` | Configure grafana datasources (passed through tpl) | `{}` |
+| `alerting` | Configure grafana alerting (passed through tpl) | `{}` |
+| `notifiers` | Configure grafana notifiers | `{}` |
+| `dashboardProviders` | Configure grafana dashboard providers | `{}` |
+| `dashboards` | Dashboards to import | `{}` |
+| `dashboardsConfigMaps` | ConfigMaps reference that contains dashboards | `{}` |
+| `grafana.ini` | Grafana's primary configuration | `{}` |
+| `ldap.enabled` | Enable LDAP authentication | `false` |
+| `ldap.existingSecret` | The name of an existing secret containing the `ldap.toml` file, this must have the key `ldap-toml`. | `""` |
+| `ldap.config` | Grafana's LDAP configuration | `""` |
+| `annotations` | Deployment annotations | `{}` |
+| `labels` | Deployment labels | `{}` |
+| `podAnnotations` | Pod annotations | `{}` |
+| `podLabels` | Pod labels | `{}` |
+| `podPortName` | Name of the grafana port on the pod | `grafana` |
+| `lifecycleHooks` | Lifecycle hooks for podStart and preStop [Example](https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/#define-poststart-and-prestop-handlers) | `{}` |
+| `sidecar.image.repository` | Sidecar image repository | `quay.io/kiwigrid/k8s-sidecar` |
+| `sidecar.image.tag` | Sidecar image tag | `1.19.2` |
+| `sidecar.image.sha` | Sidecar image sha (optional) | `""` |
+| `sidecar.imagePullPolicy` | Sidecar image pull policy | `IfNotPresent` |
+| `sidecar.resources` | Sidecar resources | `{}` |
+| `sidecar.securityContext` | Sidecar securityContext | `{}` |
+| `sidecar.enableUniqueFilenames` | Sets the kiwigrid/k8s-sidecar UNIQUE_FILENAMES environment variable. If set to `true` the sidecar will create unique filenames where duplicate data keys exist between ConfigMaps and/or Secrets within the same or multiple Namespaces. | `false` |
+| `sidecar.alerts.enabled` | Enables the cluster wide search for alerts and adds/updates/deletes them in grafana |`false` |
+| `sidecar.alerts.label` | Label that config maps with alerts should have to be added | `grafana_alert` |
+| `sidecar.alerts.labelValue` | Label value that config maps with alerts should have to be added | `""` |
+| `sidecar.alerts.searchNamespace` | Namespaces list. If specified, the sidecar will search for alerts config-maps inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces. | `nil` |
+| `sidecar.alerts.watchMethod` | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` |
+| `sidecar.alerts.resource` | Should the sidecar looks into secrets, configmaps or both. | `both` |
+| `sidecar.alerts.reloadURL` | Full url of datasource configuration reload API endpoint, to invoke after a config-map change | `"http://localhost:3000/api/admin/provisioning/alerting/reload"` |
+| `sidecar.alerts.skipReload` | Enabling this omits defining the REQ_URL and REQ_METHOD environment variables | `false` |
+| `sidecar.alerts.initDatasources` | Set to true to deploy the datasource sidecar as an initContainer in addition to a container. This is needed if skipReload is true, to load any alerts defined at startup time. | `false` |
+| `sidecar.dashboards.enabled` | Enables the cluster wide search for dashboards and adds/updates/deletes them in grafana | `false` |
+| `sidecar.dashboards.SCProvider` | Enables creation of sidecar provider | `true` |
+| `sidecar.dashboards.provider.name` | Unique name of the grafana provider | `sidecarProvider` |
+| `sidecar.dashboards.provider.orgid` | Id of the organisation, to which the dashboards should be added | `1` |
+| `sidecar.dashboards.provider.folder` | Logical folder in which grafana groups dashboards | `""` |
+| `sidecar.dashboards.provider.disableDelete` | Activate to avoid the deletion of imported dashboards | `false` |
+| `sidecar.dashboards.provider.allowUiUpdates` | Allow updating provisioned dashboards from the UI | `false` |
+| `sidecar.dashboards.provider.type` | Provider type | `file` |
+| `sidecar.dashboards.provider.foldersFromFilesStructure` | Allow Grafana to replicate dashboard structure from filesystem. | `false` |
+| `sidecar.dashboards.watchMethod` | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` |
+| `sidecar.skipTlsVerify` | Set to true to skip tls verification for kube api calls | `nil` |
+| `sidecar.dashboards.label` | Label that config maps with dashboards should have to be added | `grafana_dashboard` |
+| `sidecar.dashboards.labelValue` | Label value that config maps with dashboards should have to be added | `""` |
+| `sidecar.dashboards.folder` | Folder in the pod that should hold the collected dashboards (unless `sidecar.dashboards.defaultFolderName` is set). This path will be mounted. | `/tmp/dashboards` |
+| `sidecar.dashboards.folderAnnotation` | The annotation the sidecar will look for in configmaps to override the destination folder for files | `nil` |
+| `sidecar.dashboards.defaultFolderName` | The default folder name, it will create a subfolder under the `sidecar.dashboards.folder` and put dashboards in there instead | `nil` |
+| `sidecar.dashboards.searchNamespace` | Namespaces list. If specified, the sidecar will search for dashboards config-maps inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces. | `nil` |
+| `sidecar.dashboards.script` | Absolute path to shell script to execute after a configmap got reloaded. | `nil` |
+| `sidecar.dashboards.resource` | Should the sidecar looks into secrets, configmaps or both. | `both` |
+| `sidecar.dashboards.extraMounts` | Additional dashboard sidecar volume mounts. | `[]` |
+| `sidecar.datasources.enabled` | Enables the cluster wide search for datasources and adds/updates/deletes them in grafana |`false` |
+| `sidecar.datasources.label` | Label that config maps with datasources should have to be added | `grafana_datasource` |
+| `sidecar.datasources.labelValue` | Label value that config maps with datasources should have to be added | `""` |
+| `sidecar.datasources.searchNamespace` | Namespaces list. If specified, the sidecar will search for datasources config-maps inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces. | `nil` |
+| `sidecar.datasources.watchMethod` | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` |
+| `sidecar.datasources.resource` | Should the sidecar looks into secrets, configmaps or both. | `both` |
+| `sidecar.datasources.reloadURL` | Full url of datasource configuration reload API endpoint, to invoke after a config-map change | `"http://localhost:3000/api/admin/provisioning/datasources/reload"` |
+| `sidecar.datasources.skipReload` | Enabling this omits defining the REQ_URL and REQ_METHOD environment variables | `false` |
+| `sidecar.datasources.initDatasources` | Set to true to deploy the datasource sidecar as an initContainer in addition to a container. This is needed if skipReload is true, to load any datasources defined at startup time. | `false` |
+| `sidecar.notifiers.enabled` | Enables the cluster wide search for notifiers and adds/updates/deletes them in grafana | `false` |
+| `sidecar.notifiers.label` | Label that config maps with notifiers should have to be added | `grafana_notifier` |
+| `sidecar.notifiers.labelValue` | Label value that config maps with notifiers should have to be added | `""` |
+| `sidecar.notifiers.searchNamespace` | Namespaces list. If specified, the sidecar will search for notifiers config-maps (or secrets) inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces. | `nil` |
+| `sidecar.notifiers.watchMethod` | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` |
+| `sidecar.notifiers.resource` | Should the sidecar looks into secrets, configmaps or both. | `both` |
+| `sidecar.notifiers.reloadURL` | Full url of notifier configuration reload API endpoint, to invoke after a config-map change | `"http://localhost:3000/api/admin/provisioning/notifications/reload"` |
+| `sidecar.notifiers.skipReload` | Enabling this omits defining the REQ_URL and REQ_METHOD environment variables | `false` |
+| `sidecar.notifiers.initNotifiers` | Set to true to deploy the notifier sidecar as an initContainer in addition to a container. This is needed if skipReload is true, to load any notifiers defined at startup time. | `false` |
+| `smtp.existingSecret` | The name of an existing secret containing the SMTP credentials. | `""` |
+| `smtp.userKey` | The key in the existing SMTP secret containing the username. | `"user"` |
+| `smtp.passwordKey` | The key in the existing SMTP secret containing the password. | `"password"` |
+| `admin.existingSecret` | The name of an existing secret containing the admin credentials (can be templated). | `""` |
+| `admin.userKey` | The key in the existing admin secret containing the username. | `"admin-user"` |
+| `admin.passwordKey` | The key in the existing admin secret containing the password. | `"admin-password"` |
+| `serviceAccount.autoMount` | Automount the service account token in the pod| `true` |
+| `serviceAccount.annotations` | ServiceAccount annotations | |
+| `serviceAccount.create` | Create service account | `true` |
+| `serviceAccount.name` | Service account name to use, when empty will be set to created account if `serviceAccount.create` is set else to `default` | `` |
+| `serviceAccount.nameTest` | Service account name to use for test, when empty will be set to created account if `serviceAccount.create` is set else to `default` | `nil` |
+| `rbac.create` | Create and use RBAC resources | `true` |
+| `rbac.namespaced` | Creates Role and Rolebinding instead of the default ClusterRole and ClusteRoleBindings for the grafana instance | `false` |
+| `rbac.useExistingRole` | Set to a rolename to use existing role - skipping role creating - but still doing serviceaccount and rolebinding to the rolename set here. | `nil` |
+| `rbac.pspEnabled` | Create PodSecurityPolicy (with `rbac.create`, grant roles permissions as well) | `true` |
+| `rbac.pspUseAppArmor` | Enforce AppArmor in created PodSecurityPolicy (requires `rbac.pspEnabled`) | `true` |
+| `rbac.extraRoleRules` | Additional rules to add to the Role | [] |
+| `rbac.extraClusterRoleRules` | Additional rules to add to the ClusterRole | [] |
+| `command` | Define command to be executed by grafana container at startup | `nil` |
+| `testFramework.enabled` | Whether to create test-related resources | `true` |
+| `testFramework.image` | `test-framework` image repository. | `bats/bats` |
+| `testFramework.tag` | `test-framework` image tag. | `v1.4.1` |
+| `testFramework.imagePullPolicy` | `test-framework` image pull policy. | `IfNotPresent` |
+| `testFramework.securityContext` | `test-framework` securityContext | `{}` |
+| `downloadDashboards.env` | Environment variables to be passed to the `download-dashboards` container | `{}` |
+| `downloadDashboards.envFromSecret` | Name of a Kubernetes secret (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `""` |
+| `downloadDashboards.resources` | Resources of `download-dashboards` container | `{}` |
+| `downloadDashboardsImage.repository` | Curl docker image repo | `curlimages/curl` |
+| `downloadDashboardsImage.tag` | Curl docker image tag | `7.73.0` |
+| `downloadDashboardsImage.sha` | Curl docker image sha (optional) | `""` |
+| `downloadDashboardsImage.pullPolicy` | Curl docker image pull policy | `IfNotPresent` |
+| `namespaceOverride` | Override the deployment namespace | `""` (`Release.Namespace`) |
+| `serviceMonitor.enabled` | Use servicemonitor from prometheus operator | `false` |
+| `serviceMonitor.namespace` | Namespace this servicemonitor is installed in | |
+| `serviceMonitor.interval` | How frequently Prometheus should scrape | `1m` |
+| `serviceMonitor.path` | Path to scrape | `/metrics` |
+| `serviceMonitor.scheme` | Scheme to use for metrics scraping | `http` |
+| `serviceMonitor.tlsConfig` | TLS configuration block for the endpoint | `{}` |
+| `serviceMonitor.labels` | Labels for the servicemonitor passed to Prometheus Operator | `{}` |
+| `serviceMonitor.scrapeTimeout` | Timeout after which the scrape is ended | `30s` |
+| `serviceMonitor.relabelings` | MetricRelabelConfigs to apply to samples before ingestion. | `[]` |
+| `revisionHistoryLimit` | Number of old ReplicaSets to retain | `10` |
+| `imageRenderer.enabled` | Enable the image-renderer deployment & service | `false` |
+| `imageRenderer.image.repository` | image-renderer Image repository | `grafana/grafana-image-renderer` |
+| `imageRenderer.image.tag` | image-renderer Image tag | `latest` |
+| `imageRenderer.image.sha` | image-renderer Image sha (optional) | `""` |
+| `imageRenderer.image.pullPolicy` | image-renderer ImagePullPolicy | `Always` |
+| `imageRenderer.env` | extra env-vars for image-renderer | `{}` |
+| `imageRenderer.serviceAccountName` | image-renderer deployment serviceAccountName | `""` |
+| `imageRenderer.securityContext` | image-renderer deployment securityContext | `{}` |
+| `imageRenderer.hostAliases` | image-renderer deployment Host Aliases | `[]` |
+| `imageRenderer.priorityClassName` | image-renderer deployment priority class | `''` |
+| `imageRenderer.service.enabled` | Enable the image-renderer service | `true` |
+| `imageRenderer.service.portName` | image-renderer service port name | `http` |
+| `imageRenderer.service.port` | image-renderer port used by deployment | `8081` |
+| `imageRenderer.service.targetPort` | image-renderer service port used by service | `8081` |
+| `imageRenderer.appProtocol` | Adds the appProtocol field to the service | `` |
+| `imageRenderer.grafanaSubPath` | Grafana sub path to use for image renderer callback url | `''` |
+| `imageRenderer.podPortName` | name of the image-renderer port on the pod | `http` |
+| `imageRenderer.revisionHistoryLimit` | number of image-renderer replica sets to keep | `10` |
+| `imageRenderer.networkPolicy.limitIngress` | Enable a NetworkPolicy to limit inbound traffic from only the created grafana pods | `true` |
+| `imageRenderer.networkPolicy.limitEgress` | Enable a NetworkPolicy to limit outbound traffic to only the created grafana pods | `false` |
+| `imageRenderer.resources` | Set resource limits for image-renderer pdos | `{}` |
+| `imageRenderer.nodeSelector` | Node labels for pod assignment | `{}` |
+| `imageRenderer.tolerations` | Toleration labels for pod assignment | `[]` |
+| `imageRenderer.affinity` | Affinity settings for pod assignment | `{}` |
+| `networkPolicy.enabled` | Enable creation of NetworkPolicy resources. | `false` |
+| `networkPolicy.allowExternal` | Don't require client label for connections | `true` |
+| `networkPolicy.explicitNamespacesSelector` | A Kubernetes LabelSelector to explicitly select namespaces from which traffic could be allowed | `{}` |
+| `networkPolicy.ingress` | Enable the creation of an ingress network policy | `true` |
+| `networkPolicy.egress.enabled` | Enable the creation of an egress network policy | `false` |
+| `networkPolicy.egress.ports` | An array of ports to allow for the egress | `[]` |
+| `enableKubeBackwardCompatibility` | Enable backward compatibility of kubernetes where pod's defintion version below 1.13 doesn't have the enableServiceLinks option | `false` |
+
+
+
+### Example ingress with path
+
+With grafana 6.3 and above
+```yaml
+grafana.ini:
+ server:
+ domain: monitoring.example.com
+ root_url: "%(protocol)s://%(domain)s/grafana"
+ serve_from_sub_path: true
+ingress:
+ enabled: true
+ hosts:
+ - "monitoring.example.com"
+ path: "/grafana"
+```
+
+### Example of extraVolumeMounts
+
+Volume can be type persistentVolumeClaim or hostPath but not both at same time.
+If neither existingClaim or hostPath argument is given then type is emptyDir.
+
+```yaml
+- extraVolumeMounts:
+ - name: plugins
+ mountPath: /var/lib/grafana/plugins
+ subPath: configs/grafana/plugins
+ existingClaim: existing-grafana-claim
+ readOnly: false
+ - name: dashboards
+ mountPath: /var/lib/grafana/dashboards
+ hostPath: /usr/shared/grafana/dashboards
+ readOnly: false
+```
+
+## Import dashboards
+
+There are a few methods to import dashboards to Grafana. Below are some examples and explanations as to how to use each method:
+
+```yaml
+dashboards:
+ default:
+ some-dashboard:
+ json: |
+ {
+ "annotations":
+
+ ...
+ # Complete json file here
+ ...
+
+ "title": "Some Dashboard",
+ "uid": "abcd1234",
+ "version": 1
+ }
+ custom-dashboard:
+ # This is a path to a file inside the dashboards directory inside the chart directory
+ file: dashboards/custom-dashboard.json
+ prometheus-stats:
+ # Ref: https://grafana.com/dashboards/2
+ gnetId: 2
+ revision: 2
+ datasource: Prometheus
+ local-dashboard:
+ url: https://raw.githubusercontent.com/user/repository/master/dashboards/dashboard.json
+```
+
+## BASE64 dashboards
+
+Dashboards could be stored on a server that does not return JSON directly and instead of it returns a Base64 encoded file (e.g. Gerrit)
+A new parameter has been added to the url use case so if you specify a b64content value equals to true after the url entry a Base64 decoding is applied before save the file to disk.
+If this entry is not set or is equals to false not decoding is applied to the file before saving it to disk.
+
+### Gerrit use case
+
+Gerrit API for download files has the following schema: where {project-name} and
+{file-id} usually has '/' in their values and so they MUST be replaced by %2F so if project-name is user/repo, branch-id is master and file-id is equals to dir1/dir2/dashboard
+the url value is
+
+## Sidecar for dashboards
+
+If the parameter `sidecar.dashboards.enabled` is set, a sidecar container is deployed in the grafana
+pod. This container watches all configmaps (or secrets) in the cluster and filters out the ones with
+a label as defined in `sidecar.dashboards.label`. The files defined in those configmaps are written
+to a folder and accessed by grafana. Changes to the configmaps are monitored and the imported
+dashboards are deleted/updated.
+
+A recommendation is to use one configmap per dashboard, as a reduction of multiple dashboards inside
+one configmap is currently not properly mirrored in grafana.
+
+Example dashboard config:
+
+```yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: sample-grafana-dashboard
+ labels:
+ grafana_dashboard: "1"
+data:
+ k8s-dashboard.json: |-
+ [...]
+```
+
+## Sidecar for datasources
+
+If the parameter `sidecar.datasources.enabled` is set, an init container is deployed in the grafana
+pod. This container lists all secrets (or configmaps, though not recommended) in the cluster and
+filters out the ones with a label as defined in `sidecar.datasources.label`. The files defined in
+those secrets are written to a folder and accessed by grafana on startup. Using these yaml files,
+the data sources in grafana can be imported.
+
+Secrets are recommended over configmaps for this usecase because datasources usually contain private
+data like usernames and passwords. Secrets are the more appropriate cluster resource to manage those.
+
+Example values to add a datasource adapted from [Grafana](http://docs.grafana.org/administration/provisioning/#example-datasource-config-file):
+
+```yaml
+datasources:
+ datasources.yaml:
+ apiVersion: 1
+ datasources:
+ # name of the datasource. Required
+ - name: Graphite
+ # datasource type. Required
+ type: graphite
+ # access mode. proxy or direct (Server or Browser in the UI). Required
+ access: proxy
+ # org id. will default to orgId 1 if not specified
+ orgId: 1
+ # url
+ url: http://localhost:8080
+ # database password, if used
+ password:
+ # database user, if used
+ user:
+ # database name, if used
+ database:
+ # enable/disable basic auth
+ basicAuth:
+ # basic auth username
+ basicAuthUser:
+ # basic auth password
+ basicAuthPassword:
+ # enable/disable with credentials headers
+ withCredentials:
+ # mark as default datasource. Max one per org
+ isDefault:
+ # fields that will be converted to json and stored in json_data
+ jsonData:
+ graphiteVersion: "1.1"
+ tlsAuth: true
+ tlsAuthWithCACert: true
+ # json object of data that will be encrypted.
+ secureJsonData:
+ tlsCACert: "..."
+ tlsClientCert: "..."
+ tlsClientKey: "..."
+ version: 1
+ # allow users to edit datasources from the UI.
+ editable: false
+```
+
+## Sidecar for notifiers
+
+If the parameter `sidecar.notifiers.enabled` is set, an init container is deployed in the grafana
+pod. This container lists all secrets (or configmaps, though not recommended) in the cluster and
+filters out the ones with a label as defined in `sidecar.notifiers.label`. The files defined in
+those secrets are written to a folder and accessed by grafana on startup. Using these yaml files,
+the notification channels in grafana can be imported. The secrets must be created before
+`helm install` so that the notifiers init container can list the secrets.
+
+Secrets are recommended over configmaps for this usecase because alert notification channels usually contain
+private data like SMTP usernames and passwords. Secrets are the more appropriate cluster resource to manage those.
+
+Example datasource config adapted from [Grafana](https://grafana.com/docs/grafana/latest/administration/provisioning/#alert-notification-channels):
+
+```yaml
+notifiers:
+ - name: notification-channel-1
+ type: slack
+ uid: notifier1
+ # either
+ org_id: 2
+ # or
+ org_name: Main Org.
+ is_default: true
+ send_reminder: true
+ frequency: 1h
+ disable_resolve_message: false
+ # See `Supported Settings` section for settings supporter for each
+ # alert notification type.
+ settings:
+ recipient: 'XXX'
+ token: 'xoxb'
+ uploadImage: true
+ url: https://slack.com
+
+delete_notifiers:
+ - name: notification-channel-1
+ uid: notifier1
+ org_id: 2
+ - name: notification-channel-2
+ # default org_id: 1
+```
+
+## How to serve Grafana with a path prefix (/grafana)
+
+In order to serve Grafana with a prefix (e.g., ), add the following to your values.yaml.
+
+```yaml
+ingress:
+ enabled: true
+ annotations:
+ kubernetes.io/ingress.class: "nginx"
+ nginx.ingress.kubernetes.io/rewrite-target: /$1
+ nginx.ingress.kubernetes.io/use-regex: "true"
+
+ path: /grafana/?(.*)
+ hosts:
+ - k8s.example.dev
+
+grafana.ini:
+ server:
+ root_url: http://localhost:3000/grafana # this host can be localhost
+```
+
+## How to securely reference secrets in grafana.ini
+
+This example uses Grafana [file providers](https://grafana.com/docs/grafana/latest/administration/configuration/#file-provider) for secret values and the `extraSecretMounts` configuration flag (Additional grafana server secret mounts) to mount the secrets.
+
+In grafana.ini:
+
+```yaml
+grafana.ini:
+ [auth.generic_oauth]
+ enabled = true
+ client_id = $__file{/etc/secrets/auth_generic_oauth/client_id}
+ client_secret = $__file{/etc/secrets/auth_generic_oauth/client_secret}
+```
+
+Existing secret, or created along with helm:
+
+```yaml
+---
+apiVersion: v1
+kind: Secret
+metadata:
+ name: auth-generic-oauth-secret
+type: Opaque
+stringData:
+ client_id:
+ client_secret:
+```
+
+Include in the `extraSecretMounts` configuration flag:
+
+```yaml
+- extraSecretMounts:
+ - name: auth-generic-oauth-secret-mount
+ secretName: auth-generic-oauth-secret
+ defaultMode: 0440
+ mountPath: /etc/secrets/auth_generic_oauth
+ readOnly: true
+```
+
+### extraSecretMounts using a Container Storage Interface (CSI) provider
+
+This example uses a CSI driver e.g. retrieving secrets using [Azure Key Vault Provider](https://github.com/Azure/secrets-store-csi-driver-provider-azure)
+
+```yaml
+- extraSecretMounts:
+ - name: secrets-store-inline
+ mountPath: /run/secrets
+ readOnly: true
+ csi:
+ driver: secrets-store.csi.k8s.io
+ readOnly: true
+ volumeAttributes:
+ secretProviderClass: "my-provider"
+ nodePublishSecretRef:
+ name: akv-creds
+```
+
+## Image Renderer Plug-In
+
+This chart supports enabling [remote image rendering](https://github.com/grafana/grafana-image-renderer/blob/master/README.md#run-in-docker)
+
+```yaml
+imageRenderer:
+ enabled: true
+```
+
+### Image Renderer NetworkPolicy
+
+By default the image-renderer pods will have a network policy which only allows ingress traffic from the created grafana instance
+
+### High Availability for unified alerting
+
+If you want to run Grafana in a high availability cluster you need to enable
+the headless service by setting `headlessService: true` in your `values.yaml`
+file.
+
+As next step you have to setup the `grafana.ini` in your `values.yaml` in a way
+that it will make use of the headless service to obtain all the IPs of the
+cluster. You should replace ``{{ Name }}`` with the name of your helm deployment.
+
+```yaml
+grafana.ini:
+ ...
+ unified_alerting:
+ enabled: true
+ ha_peers: {{ Name }}-headless:9094
+ alerting:
+ enabled: false
+```
diff --git a/kube-prometheus-stack/charts/grafana/ci/default-values.yaml b/kube-prometheus-stack/charts/grafana/ci/default-values.yaml
new file mode 100644
index 00000000..fc2ba605
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/ci/default-values.yaml
@@ -0,0 +1 @@
+# Leave this file empty to ensure that CI runs builds against the default configuration in values.yaml.
diff --git a/kube-prometheus-stack/charts/grafana/ci/with-affinity-values.yaml b/kube-prometheus-stack/charts/grafana/ci/with-affinity-values.yaml
new file mode 100644
index 00000000..f5b9b53e
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/ci/with-affinity-values.yaml
@@ -0,0 +1,16 @@
+affinity:
+ podAntiAffinity:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ - podAffinityTerm:
+ labelSelector:
+ matchLabels:
+ app.kubernetes.io/instance: grafana-test
+ app.kubernetes.io/name: grafana
+ topologyKey: failure-domain.beta.kubernetes.io/zone
+ weight: 100
+ requiredDuringSchedulingIgnoredDuringExecution:
+ - labelSelector:
+ matchLabels:
+ app.kubernetes.io/instance: grafana-test
+ app.kubernetes.io/name: grafana
+ topologyKey: kubernetes.io/hostname
diff --git a/kube-prometheus-stack/charts/grafana/ci/with-dashboard-json-values.yaml b/kube-prometheus-stack/charts/grafana/ci/with-dashboard-json-values.yaml
new file mode 100644
index 00000000..e0c4e416
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/ci/with-dashboard-json-values.yaml
@@ -0,0 +1,53 @@
+dashboards:
+ my-provider:
+ my-awesome-dashboard:
+ # An empty but valid dashboard
+ json: |
+ {
+ "__inputs": [],
+ "__requires": [
+ {
+ "type": "grafana",
+ "id": "grafana",
+ "name": "Grafana",
+ "version": "6.3.5"
+ }
+ ],
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "id": null,
+ "links": [],
+ "panels": [],
+ "schemaVersion": 19,
+ "style": "dark",
+ "tags": [],
+ "templating": {
+ "list": []
+ },
+ "time": {
+ "from": "now-6h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": ["5s"]
+ },
+ "timezone": "",
+ "title": "Dummy Dashboard",
+ "uid": "IdcYQooWk",
+ "version": 1
+ }
+ datasource: Prometheus
diff --git a/kube-prometheus-stack/charts/grafana/ci/with-dashboard-values.yaml b/kube-prometheus-stack/charts/grafana/ci/with-dashboard-values.yaml
new file mode 100644
index 00000000..7b662c5f
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/ci/with-dashboard-values.yaml
@@ -0,0 +1,19 @@
+dashboards:
+ my-provider:
+ my-awesome-dashboard:
+ gnetId: 10000
+ revision: 1
+ datasource: Prometheus
+dashboardProviders:
+ dashboardproviders.yaml:
+ apiVersion: 1
+ providers:
+ - name: 'my-provider'
+ orgId: 1
+ folder: ''
+ type: file
+ updateIntervalSeconds: 10
+ disableDeletion: true
+ editable: true
+ options:
+ path: /var/lib/grafana/dashboards/my-provider
diff --git a/kube-prometheus-stack/charts/grafana/ci/with-extraconfigmapmounts-values.yaml b/kube-prometheus-stack/charts/grafana/ci/with-extraconfigmapmounts-values.yaml
new file mode 100644
index 00000000..f2d55a83
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/ci/with-extraconfigmapmounts-values.yaml
@@ -0,0 +1,7 @@
+extraConfigmapMounts:
+ - name: '{{ template "grafana.fullname" . }}'
+ configMap: '{{ template "grafana.fullname" . }}'
+ mountPath: /var/lib/grafana/dashboards/test-dashboard.json
+ # This is not a realistic test, but for this we only care about extraConfigmapMounts not being empty and pointing to an existing ConfigMap
+ subPath: grafana.ini
+ readOnly: true
diff --git a/kube-prometheus-stack/charts/grafana/ci/with-image-renderer-values.yaml b/kube-prometheus-stack/charts/grafana/ci/with-image-renderer-values.yaml
new file mode 100644
index 00000000..32f30743
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/ci/with-image-renderer-values.yaml
@@ -0,0 +1,19 @@
+podLabels:
+ customLableA: Aaaaa
+imageRenderer:
+ enabled: true
+ env:
+ RENDERING_ARGS: --disable-gpu,--window-size=1280x758
+ RENDERING_MODE: clustered
+ podLabels:
+ customLableB: Bbbbb
+ networkPolicy:
+ limitIngress: true
+ limitEgress: true
+ resources:
+ limits:
+ cpu: 1000m
+ memory: 1000Mi
+ requests:
+ cpu: 500m
+ memory: 50Mi
diff --git a/kube-prometheus-stack/charts/grafana/ci/with-persistence.yaml b/kube-prometheus-stack/charts/grafana/ci/with-persistence.yaml
new file mode 100644
index 00000000..b92ca02c
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/ci/with-persistence.yaml
@@ -0,0 +1,3 @@
+persistence:
+ type: pvc
+ enabled: true
diff --git a/kube-prometheus-stack/charts/grafana/dashboards/custom-dashboard.json b/kube-prometheus-stack/charts/grafana/dashboards/custom-dashboard.json
new file mode 100644
index 00000000..9e26dfee
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/dashboards/custom-dashboard.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/kube-prometheus-stack/charts/grafana/templates/NOTES.txt b/kube-prometheus-stack/charts/grafana/templates/NOTES.txt
new file mode 100644
index 00000000..1fc8436d
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/NOTES.txt
@@ -0,0 +1,54 @@
+1. Get your '{{ .Values.adminUser }}' user password by running:
+
+ kubectl get secret --namespace {{ template "grafana.namespace" . }} {{ template "grafana.fullname" . }} -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
+
+2. The Grafana server can be accessed via port {{ .Values.service.port }} on the following DNS name from within your cluster:
+
+ {{ template "grafana.fullname" . }}.{{ template "grafana.namespace" . }}.svc.cluster.local
+{{ if .Values.ingress.enabled }}
+ If you bind grafana to 80, please update values in values.yaml and reinstall:
+ ```
+ securityContext:
+ runAsUser: 0
+ runAsGroup: 0
+ fsGroup: 0
+
+ command:
+ - "setcap"
+ - "'cap_net_bind_service=+ep'"
+ - "/usr/sbin/grafana-server &&"
+ - "sh"
+ - "/run.sh"
+ ```
+ Details refer to https://grafana.com/docs/installation/configuration/#http-port.
+ Or grafana would always crash.
+
+ From outside the cluster, the server URL(s) are:
+{{- range .Values.ingress.hosts }}
+ http://{{ . }}
+{{- end }}
+{{ else }}
+ Get the Grafana URL to visit by running these commands in the same shell:
+{{ if contains "NodePort" .Values.service.type -}}
+ export NODE_PORT=$(kubectl get --namespace {{ template "grafana.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "grafana.fullname" . }})
+ export NODE_IP=$(kubectl get nodes --namespace {{ template "grafana.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}")
+ echo http://$NODE_IP:$NODE_PORT
+{{ else if contains "LoadBalancer" .Values.service.type -}}
+ NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+ You can watch the status of by running 'kubectl get svc --namespace {{ template "grafana.namespace" . }} -w {{ template "grafana.fullname" . }}'
+ export SERVICE_IP=$(kubectl get svc --namespace {{ template "grafana.namespace" . }} {{ template "grafana.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
+ http://$SERVICE_IP:{{ .Values.service.port -}}
+{{ else if contains "ClusterIP" .Values.service.type }}
+ export POD_NAME=$(kubectl get pods --namespace {{ template "grafana.namespace" . }} -l "app.kubernetes.io/name={{ template "grafana.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+ kubectl --namespace {{ template "grafana.namespace" . }} port-forward $POD_NAME 3000
+{{- end }}
+{{- end }}
+
+3. Login with the password from step 1 and the username: {{ .Values.adminUser }}
+
+{{- if not .Values.persistence.enabled }}
+#################################################################################
+###### WARNING: Persistence is disabled!!! You will lose your data when #####
+###### the Grafana pod is terminated. #####
+#################################################################################
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/_helpers.tpl b/kube-prometheus-stack/charts/grafana/templates/_helpers.tpl
new file mode 100644
index 00000000..369e69fa
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/_helpers.tpl
@@ -0,0 +1,174 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "grafana.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 "grafana.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 "grafana.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create the name of the service account
+*/}}
+{{- define "grafana.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+ {{ default (include "grafana.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+ {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
+
+{{- define "grafana.serviceAccountNameTest" -}}
+{{- if .Values.serviceAccount.create -}}
+ {{ default (print (include "grafana.fullname" .) "-test") .Values.serviceAccount.nameTest }}
+{{- else -}}
+ {{ default "default" .Values.serviceAccount.nameTest }}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Allow the release namespace to be overridden for multi-namespace deployments in combined charts
+*/}}
+{{- define "grafana.namespace" -}}
+ {{- if .Values.namespaceOverride -}}
+ {{- .Values.namespaceOverride -}}
+ {{- else -}}
+ {{- .Release.Namespace -}}
+ {{- end -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "grafana.labels" -}}
+helm.sh/chart: {{ include "grafana.chart" . }}
+{{ include "grafana.selectorLabels" . }}
+{{- if or .Chart.AppVersion .Values.image.tag }}
+app.kubernetes.io/version: {{ .Values.image.tag | default .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- if .Values.extraLabels }}
+{{ toYaml .Values.extraLabels }}
+{{- end }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "grafana.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "grafana.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "grafana.imageRenderer.labels" -}}
+helm.sh/chart: {{ include "grafana.chart" . }}
+{{ include "grafana.imageRenderer.selectorLabels" . }}
+{{- if or .Chart.AppVersion .Values.image.tag }}
+app.kubernetes.io/version: {{ .Values.image.tag | default .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels ImageRenderer
+*/}}
+{{- define "grafana.imageRenderer.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "grafana.name" . }}-image-renderer
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Looks if there's an existing secret and reuse its password. If not it generates
+new password and use it.
+*/}}
+{{- define "grafana.password" -}}
+{{- $secret := (lookup "v1" "Secret" (include "grafana.namespace" .) (include "grafana.fullname" .) ) -}}
+ {{- if $secret -}}
+ {{- index $secret "data" "admin-password" -}}
+ {{- else -}}
+ {{- (randAlphaNum 40) | b64enc | quote -}}
+ {{- end -}}
+{{- end -}}
+
+{{/*
+Return the appropriate apiVersion for rbac.
+*/}}
+{{- define "grafana.rbac.apiVersion" -}}
+ {{- if .Capabilities.APIVersions.Has "rbac.authorization.k8s.io/v1" }}
+ {{- print "rbac.authorization.k8s.io/v1" -}}
+ {{- else -}}
+ {{- print "rbac.authorization.k8s.io/v1beta1" -}}
+ {{- end -}}
+{{- end -}}
+
+{{/*
+Return the appropriate apiVersion for ingress.
+*/}}
+{{- define "grafana.ingress.apiVersion" -}}
+ {{- if and (.Capabilities.APIVersions.Has "networking.k8s.io/v1") (semverCompare ">= 1.19-0" .Capabilities.KubeVersion.Version) -}}
+ {{- print "networking.k8s.io/v1" -}}
+ {{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
+ {{- print "networking.k8s.io/v1beta1" -}}
+ {{- else -}}
+ {{- print "extensions/v1beta1" -}}
+ {{- end -}}
+{{- end -}}
+
+{{/*
+Return the appropriate apiVersion for podDisruptionBudget.
+*/}}
+{{- define "grafana.podDisruptionBudget.apiVersion" -}}
+ {{- if $.Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" -}}
+ {{- print "policy/v1" -}}
+ {{- else -}}
+ {{- print "policy/v1beta1" -}}
+ {{- end -}}
+{{- end -}}
+
+{{/*
+Return if ingress is stable.
+*/}}
+{{- define "grafana.ingress.isStable" -}}
+ {{- eq (include "grafana.ingress.apiVersion" .) "networking.k8s.io/v1" -}}
+{{- end -}}
+
+{{/*
+Return if ingress supports ingressClassName.
+*/}}
+{{- define "grafana.ingress.supportsIngressClassName" -}}
+ {{- or (eq (include "grafana.ingress.isStable" .) "true") (and (eq (include "grafana.ingress.apiVersion" .) "networking.k8s.io/v1beta1") (semverCompare ">= 1.18-0" .Capabilities.KubeVersion.Version)) -}}
+{{- end -}}
+
+{{/*
+Return if ingress supports pathType.
+*/}}
+{{- define "grafana.ingress.supportsPathType" -}}
+ {{- or (eq (include "grafana.ingress.isStable" .) "true") (and (eq (include "grafana.ingress.apiVersion" .) "networking.k8s.io/v1beta1") (semverCompare ">= 1.18-0" .Capabilities.KubeVersion.Version)) -}}
+{{- end -}}
diff --git a/kube-prometheus-stack/charts/grafana/templates/_pod.tpl b/kube-prometheus-stack/charts/grafana/templates/_pod.tpl
new file mode 100644
index 00000000..75ab26ca
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/_pod.tpl
@@ -0,0 +1,1114 @@
+{{- define "grafana.pod" -}}
+{{- if .Values.schedulerName }}
+schedulerName: "{{ .Values.schedulerName }}"
+{{- end }}
+serviceAccountName: {{ template "grafana.serviceAccountName" . }}
+automountServiceAccountToken: {{ .Values.serviceAccount.autoMount }}
+{{- with .Values.securityContext }}
+securityContext:
+ {{- toYaml . | nindent 2 }}
+{{- end }}
+{{- with .Values.hostAliases }}
+hostAliases:
+ {{- toYaml . | nindent 2 }}
+{{- end }}
+{{- if .Values.priorityClassName }}
+priorityClassName: {{ .Values.priorityClassName }}
+{{- end }}
+{{- if ( or .Values.persistence.enabled .Values.dashboards .Values.extraInitContainers (and .Values.sidecar.datasources.enabled .Values.sidecar.datasources.initDatasources) (and .Values.sidecar.notifiers.enabled .Values.sidecar.notifiers.initNotifiers)) }}
+initContainers:
+{{- end }}
+{{- if ( and .Values.persistence.enabled .Values.initChownData.enabled ) }}
+ - name: init-chown-data
+ {{- if .Values.initChownData.image.sha }}
+ image: "{{ .Values.initChownData.image.repository }}:{{ .Values.initChownData.image.tag }}@sha256:{{ .Values.initChownData.image.sha }}"
+ {{- else }}
+ image: "{{ .Values.initChownData.image.repository }}:{{ .Values.initChownData.image.tag }}"
+ {{- end }}
+ imagePullPolicy: {{ .Values.initChownData.image.pullPolicy }}
+ securityContext:
+ runAsNonRoot: false
+ runAsUser: 0
+ command: ["chown", "-R", "{{ .Values.securityContext.runAsUser }}:{{ .Values.securityContext.runAsGroup }}", "/var/lib/grafana"]
+ {{- with .Values.initChownData.resources }}
+ resources:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ volumeMounts:
+ - name: storage
+ mountPath: "/var/lib/grafana"
+{{- if .Values.persistence.subPath }}
+ subPath: {{ tpl .Values.persistence.subPath . }}
+{{- end }}
+{{- end }}
+{{- if .Values.dashboards }}
+ - name: download-dashboards
+ {{- if .Values.downloadDashboardsImage.sha }}
+ image: "{{ .Values.downloadDashboardsImage.repository }}:{{ .Values.downloadDashboardsImage.tag }}@sha256:{{ .Values.downloadDashboardsImage.sha }}"
+ {{- else }}
+ image: "{{ .Values.downloadDashboardsImage.repository }}:{{ .Values.downloadDashboardsImage.tag }}"
+ {{- end }}
+ imagePullPolicy: {{ .Values.downloadDashboardsImage.pullPolicy }}
+ command: ["/bin/sh"]
+ args: [ "-c", "mkdir -p /var/lib/grafana/dashboards/default && /bin/sh -x /etc/grafana/download_dashboards.sh" ]
+ {{- with .Values.downloadDashboards.resources }}
+ resources:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ env:
+{{- range $key, $value := .Values.downloadDashboards.env }}
+ - name: "{{ $key }}"
+ value: "{{ $value }}"
+{{- end }}
+ {{- with .Values.downloadDashboards.securityContext }}
+ securityContext:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+{{- if .Values.downloadDashboards.envFromSecret }}
+ envFrom:
+ - secretRef:
+ name: {{ tpl .Values.downloadDashboards.envFromSecret . }}
+{{- end }}
+ volumeMounts:
+ - name: config
+ mountPath: "/etc/grafana/download_dashboards.sh"
+ subPath: download_dashboards.sh
+ - name: storage
+ mountPath: "/var/lib/grafana"
+{{- if .Values.persistence.subPath }}
+ subPath: {{ tpl .Values.persistence.subPath . }}
+{{- end }}
+ {{- range .Values.extraSecretMounts }}
+ - name: {{ .name }}
+ mountPath: {{ .mountPath }}
+ readOnly: {{ .readOnly }}
+ {{- end }}
+{{- end }}
+{{- if and .Values.sidecar.datasources.enabled .Values.sidecar.datasources.initDatasources }}
+ - name: {{ template "grafana.name" . }}-init-sc-datasources
+ {{- if .Values.sidecar.image.sha }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}"
+ {{- else }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}"
+ {{- end }}
+ imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }}
+ env:
+ {{- range $key, $value := .Values.sidecar.datasources.env }}
+ - name: "{{ $key }}"
+ value: "{{ $value }}"
+ {{- end }}
+ {{- if .Values.sidecar.datasources.ignoreAlreadyProcessed }}
+ - name: IGNORE_ALREADY_PROCESSED
+ value: "true"
+ {{- end }}
+ - name: METHOD
+ value: "LIST"
+ - name: LABEL
+ value: "{{ .Values.sidecar.datasources.label }}"
+ {{- if .Values.sidecar.datasources.labelValue }}
+ - name: LABEL_VALUE
+ value: {{ quote .Values.sidecar.datasources.labelValue }}
+ {{- end }}
+ {{- if or .Values.sidecar.logLevel .Values.sidecar.datasources.logLevel }}
+ - name: LOG_LEVEL
+ value: {{ default .Values.sidecar.logLevel .Values.sidecar.datasources.logLevel }}
+ {{- end }}
+ - name: FOLDER
+ value: "/etc/grafana/provisioning/datasources"
+ - name: RESOURCE
+ value: {{ quote .Values.sidecar.datasources.resource }}
+ {{- if .Values.sidecar.enableUniqueFilenames }}
+ - name: UNIQUE_FILENAMES
+ value: "{{ .Values.sidecar.enableUniqueFilenames }}"
+ {{- end }}
+ {{- if .Values.sidecar.datasources.searchNamespace }}
+ - name: NAMESPACE
+ value: "{{ tpl (.Values.sidecar.datasources.searchNamespace | join ",") . }}"
+ {{- end }}
+ {{- if .Values.sidecar.skipTlsVerify }}
+ - name: SKIP_TLS_VERIFY
+ value: "{{ .Values.sidecar.skipTlsVerify }}"
+ {{- end }}
+ {{- with .Values.sidecar.resources }}
+ resources:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.securityContext }}
+ securityContext:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ volumeMounts:
+ - name: sc-datasources-volume
+ mountPath: "/etc/grafana/provisioning/datasources"
+{{- end }}
+{{- if and .Values.sidecar.notifiers.enabled .Values.sidecar.notifiers.initNotifiers }}
+ - name: {{ template "grafana.name" . }}-init-sc-notifiers
+ {{- if .Values.sidecar.image.sha }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}"
+ {{- else }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}"
+ {{- end }}
+ imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }}
+ env:
+ {{- range $key, $value := .Values.sidecar.notifiers.env }}
+ - name: "{{ $key }}"
+ value: "{{ $value }}"
+ {{- end }}
+ {{- if .Values.sidecar.notifiers.ignoreAlreadyProcessed }}
+ - name: IGNORE_ALREADY_PROCESSED
+ value: "true"
+ {{- end }}
+ - name: METHOD
+ value: LIST
+ - name: LABEL
+ value: "{{ .Values.sidecar.notifiers.label }}"
+ {{- if .Values.sidecar.notifiers.labelValue }}
+ - name: LABEL_VALUE
+ value: {{ quote .Values.sidecar.notifiers.labelValue }}
+ {{- end }}
+ {{- if or .Values.sidecar.logLevel .Values.sidecar.notifiers.logLevel }}
+ - name: LOG_LEVEL
+ value: {{ default .Values.sidecar.logLevel .Values.sidecar.notifiers.logLevel }}
+ {{- end }}
+ - name: FOLDER
+ value: "/etc/grafana/provisioning/notifiers"
+ - name: RESOURCE
+ value: {{ quote .Values.sidecar.notifiers.resource }}
+ {{- if .Values.sidecar.enableUniqueFilenames }}
+ - name: UNIQUE_FILENAMES
+ value: "{{ .Values.sidecar.enableUniqueFilenames }}"
+ {{- end }}
+ {{- if .Values.sidecar.notifiers.searchNamespace }}
+ - name: NAMESPACE
+ value: "{{ tpl (.Values.sidecar.notifiers.searchNamespace | join ",") . }}"
+ {{- end }}
+ {{- if .Values.sidecar.skipTlsVerify }}
+ - name: SKIP_TLS_VERIFY
+ value: "{{ .Values.sidecar.skipTlsVerify }}"
+ {{- end }}
+ {{- with .Values.sidecar.livenessProbe }}
+ livenessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.readinessProbe }}
+ readinessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.resources }}
+ resources:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.securityContext }}
+ securityContext:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ volumeMounts:
+ - name: sc-notifiers-volume
+ mountPath: "/etc/grafana/provisioning/notifiers"
+{{- end}}
+{{- if .Values.extraInitContainers }}
+{{ tpl (toYaml .Values.extraInitContainers) . | indent 2 }}
+{{- end }}
+{{- if .Values.image.pullSecrets }}
+imagePullSecrets:
+{{- $root := . }}
+{{- range .Values.image.pullSecrets }}
+ - name: {{ tpl . $root }}
+{{- end}}
+{{- end }}
+{{- if not .Values.enableKubeBackwardCompatibility }}
+enableServiceLinks: {{ .Values.enableServiceLinks }}
+{{- end }}
+containers:
+{{- if .Values.sidecar.alerts.enabled }}
+ - name: {{ template "grafana.name" . }}-sc-alerts
+ {{- if .Values.sidecar.image.sha }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}"
+ {{- else }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}"
+ {{- end }}
+ imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }}
+ env:
+ {{- range $key, $value := .Values.sidecar.alerts.env }}
+ - name: "{{ $key }}"
+ value: "{{ $value }}"
+ {{- end }}
+ {{- if .Values.sidecar.alerts.ignoreAlreadyProcessed }}
+ - name: IGNORE_ALREADY_PROCESSED
+ value: "true"
+ {{- end }}
+ - name: METHOD
+ value: {{ .Values.sidecar.alerts.watchMethod }}
+ - name: LABEL
+ value: "{{ .Values.sidecar.alerts.label }}"
+ {{- with .Values.sidecar.alerts.labelValue }}
+ - name: LABEL_VALUE
+ value: {{ quote . }}
+ {{- end }}
+ {{- if or .Values.sidecar.logLevel .Values.sidecar.alerts.logLevel }}
+ - name: LOG_LEVEL
+ value: {{ default .Values.sidecar.logLevel .Values.sidecar.alerts.logLevel }}
+ {{- end }}
+ - name: FOLDER
+ value: "/etc/grafana/provisioning/alerting"
+ - name: RESOURCE
+ value: {{ quote .Values.sidecar.alerts.resource }}
+ {{- if .Values.sidecar.enableUniqueFilenames }}
+ - name: UNIQUE_FILENAMES
+ value: "{{ .Values.sidecar.enableUniqueFilenames }}"
+ {{- end }}
+ {{- with .Values.sidecar.alerts.searchNamespace }}
+ - name: NAMESPACE
+ value: {{ . | join "," | quote }}
+ {{- end }}
+ {{- with .Values.sidecar.alerts.skipTlsVerify }}
+ - name: SKIP_TLS_VERIFY
+ value: {{ quote . }}
+ {{- end }}
+ {{- with .Values.sidecar.alerts.script }}
+ - name: SCRIPT
+ value: {{ quote . }}
+ {{- end }}
+ {{- if and (not .Values.env.GF_SECURITY_ADMIN_USER) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
+ - name: REQ_USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }}
+ key: {{ .Values.admin.userKey | default "admin-user" }}
+ {{- end }}
+ {{- if and (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
+ - name: REQ_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }}
+ key: {{ .Values.admin.passwordKey | default "admin-password" }}
+ {{- end }}
+ {{- if not .Values.sidecar.alerts.skipReload }}
+ - name: REQ_URL
+ value: {{ .Values.sidecar.alerts.reloadURL }}
+ - name: REQ_METHOD
+ value: POST
+ {{- end }}
+ {{- if .Values.sidecar.alerts.watchServerTimeout }}
+ {{- if ne .Values.sidecar.alerts.watchMethod "WATCH" }}
+ {{- fail (printf "Cannot use .Values.sidecar.alerts.watchServerTimeout with .Values.sidecar.alerts.watchMethod %s" .Values.sidecar.alerts.watchMethod) }}
+ {{- end }}
+ - name: WATCH_SERVER_TIMEOUT
+ value: "{{ .Values.sidecar.alerts.watchServerTimeout }}"
+ {{- end }}
+ {{- if .Values.sidecar.alerts.watchClientTimeout }}
+ {{- if ne .Values.sidecar.alerts.watchMethod "WATCH" }}
+ {{- fail (printf "Cannot use .Values.sidecar.alerts.watchClientTimeout with .Values.sidecar.alerts.watchMethod %s" .Values.sidecar.alerts.watchMethod) }}
+ {{- end }}
+ - name: WATCH_CLIENT_TIMEOUT
+ value: "{{ .Values.sidecar.alerts.watchClientTimeout }}"
+ {{- end }}
+ {{- with .Values.sidecar.livenessProbe }}
+ livenessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.readinessProbe }}
+ readinessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.resources }}
+ resources:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.securityContext }}
+ securityContext:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ volumeMounts:
+ - name: sc-alerts-volume
+ mountPath: "/etc/grafana/provisioning/alerting"
+{{- end}}
+{{- if .Values.sidecar.dashboards.enabled }}
+ - name: {{ template "grafana.name" . }}-sc-dashboard
+ {{- if .Values.sidecar.image.sha }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}"
+ {{- else }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}"
+ {{- end }}
+ imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }}
+ env:
+ {{- range $key, $value := .Values.sidecar.dashboards.env }}
+ - name: "{{ $key }}"
+ value: "{{ $value }}"
+ {{- end }}
+ {{- if .Values.sidecar.dashboards.ignoreAlreadyProcessed }}
+ - name: IGNORE_ALREADY_PROCESSED
+ value: "true"
+ {{- end }}
+ - name: METHOD
+ value: {{ .Values.sidecar.dashboards.watchMethod }}
+ - name: LABEL
+ value: "{{ .Values.sidecar.dashboards.label }}"
+ {{- if .Values.sidecar.dashboards.labelValue }}
+ - name: LABEL_VALUE
+ value: {{ quote .Values.sidecar.dashboards.labelValue }}
+ {{- end }}
+ {{- if or .Values.sidecar.logLevel .Values.sidecar.dashboards.logLevel }}
+ - name: LOG_LEVEL
+ value: {{ default .Values.sidecar.logLevel .Values.sidecar.dashboards.logLevel }}
+ {{- end }}
+ - name: FOLDER
+ value: "{{ .Values.sidecar.dashboards.folder }}{{- with .Values.sidecar.dashboards.defaultFolderName }}/{{ . }}{{- end }}"
+ - name: RESOURCE
+ value: {{ quote .Values.sidecar.dashboards.resource }}
+ {{- if .Values.sidecar.enableUniqueFilenames }}
+ - name: UNIQUE_FILENAMES
+ value: "{{ .Values.sidecar.enableUniqueFilenames }}"
+ {{- end }}
+ {{- if .Values.sidecar.dashboards.searchNamespace }}
+ - name: NAMESPACE
+ value: "{{ tpl (.Values.sidecar.dashboards.searchNamespace | join ",") . }}"
+ {{- end }}
+ {{- if .Values.sidecar.skipTlsVerify }}
+ - name: SKIP_TLS_VERIFY
+ value: "{{ .Values.sidecar.skipTlsVerify }}"
+ {{- end }}
+ {{- if .Values.sidecar.dashboards.folderAnnotation }}
+ - name: FOLDER_ANNOTATION
+ value: "{{ .Values.sidecar.dashboards.folderAnnotation }}"
+ {{- end }}
+ {{- if .Values.sidecar.dashboards.script }}
+ - name: SCRIPT
+ value: "{{ .Values.sidecar.dashboards.script }}"
+ {{- end }}
+ {{- if .Values.sidecar.dashboards.watchServerTimeout }}
+ {{- if ne .Values.sidecar.dashboards.watchMethod "WATCH" }}
+ {{- fail (printf "Cannot use .Values.sidecar.dashboards.watchServerTimeout with .Values.sidecar.dashboards.watchMethod %s" .Values.sidecar.dashboards.watchMethod) }}
+ {{- end }}
+ - name: WATCH_SERVER_TIMEOUT
+ value: "{{ .Values.sidecar.dashboards.watchServerTimeout }}"
+ {{- end }}
+ {{- if .Values.sidecar.dashboards.watchClientTimeout }}
+ {{- if ne .Values.sidecar.dashboards.watchMethod "WATCH" }}
+ {{- fail (printf "Cannot use .Values.sidecar.dashboards.watchClientTimeout with .Values.sidecar.dashboards.watchMethod %s" .Values.sidecar.dashboards.watchMethod) }}
+ {{- end }}
+ - name: WATCH_CLIENT_TIMEOUT
+ value: "{{ .Values.sidecar.dashboards.watchClientTimeout }}"
+ {{- end }}
+ {{- with .Values.sidecar.livenessProbe }}
+ livenessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.readinessProbe }}
+ readinessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.resources }}
+ resources:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.securityContext }}
+ securityContext:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ volumeMounts:
+ - name: sc-dashboard-volume
+ mountPath: {{ .Values.sidecar.dashboards.folder | quote }}
+ {{- if .Values.sidecar.dashboards.extraMounts }}
+ {{- toYaml .Values.sidecar.dashboards.extraMounts | trim | nindent 6}}
+ {{- end }}
+{{- end}}
+{{- if .Values.sidecar.datasources.enabled }}
+ - name: {{ template "grafana.name" . }}-sc-datasources
+ {{- if .Values.sidecar.image.sha }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}"
+ {{- else }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}"
+ {{- end }}
+ imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }}
+ env:
+ {{- range $key, $value := .Values.sidecar.datasources.env }}
+ - name: "{{ $key }}"
+ value: "{{ $value }}"
+ {{- end }}
+ {{- if .Values.sidecar.datasources.ignoreAlreadyProcessed }}
+ - name: IGNORE_ALREADY_PROCESSED
+ value: "true"
+ {{- end }}
+ - name: METHOD
+ value: {{ .Values.sidecar.datasources.watchMethod }}
+ - name: LABEL
+ value: "{{ .Values.sidecar.datasources.label }}"
+ {{- if .Values.sidecar.datasources.labelValue }}
+ - name: LABEL_VALUE
+ value: {{ quote .Values.sidecar.datasources.labelValue }}
+ {{- end }}
+ {{- if or .Values.sidecar.logLevel .Values.sidecar.datasources.logLevel }}
+ - name: LOG_LEVEL
+ value: {{ default .Values.sidecar.logLevel .Values.sidecar.datasources.logLevel }}
+ {{- end }}
+ - name: FOLDER
+ value: "/etc/grafana/provisioning/datasources"
+ - name: RESOURCE
+ value: {{ quote .Values.sidecar.datasources.resource }}
+ {{- if .Values.sidecar.enableUniqueFilenames }}
+ - name: UNIQUE_FILENAMES
+ value: "{{ .Values.sidecar.enableUniqueFilenames }}"
+ {{- end }}
+ {{- if .Values.sidecar.datasources.searchNamespace }}
+ - name: NAMESPACE
+ value: "{{ tpl (.Values.sidecar.datasources.searchNamespace | join ",") . }}"
+ {{- end }}
+ {{- if .Values.sidecar.skipTlsVerify }}
+ - name: SKIP_TLS_VERIFY
+ value: "{{ .Values.sidecar.skipTlsVerify }}"
+ {{- end }}
+ {{- if .Values.sidecar.datasources.script }}
+ - name: SCRIPT
+ value: "{{ .Values.sidecar.datasources.script }}"
+ {{- end }}
+ {{- if and (not .Values.env.GF_SECURITY_ADMIN_USER) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
+ - name: REQ_USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }}
+ key: {{ .Values.admin.userKey | default "admin-user" }}
+ {{- end }}
+ {{- if and (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
+ - name: REQ_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }}
+ key: {{ .Values.admin.passwordKey | default "admin-password" }}
+ {{- end }}
+ {{- if not .Values.sidecar.datasources.skipReload }}
+ - name: REQ_URL
+ value: {{ .Values.sidecar.datasources.reloadURL }}
+ - name: REQ_METHOD
+ value: POST
+ {{- end }}
+ {{- if .Values.sidecar.datasources.watchServerTimeout }}
+ {{- if ne .Values.sidecar.datasources.watchMethod "WATCH" }}
+ {{- fail (printf "Cannot use .Values.sidecar.datasources.watchServerTimeout with .Values.sidecar.datasources.watchMethod %s" .Values.sidecar.datasources.watchMethod) }}
+ {{- end }}
+ - name: WATCH_SERVER_TIMEOUT
+ value: "{{ .Values.sidecar.datasources.watchServerTimeout }}"
+ {{- end }}
+ {{- if .Values.sidecar.datasources.watchClientTimeout }}
+ {{- if ne .Values.sidecar.datasources.watchMethod "WATCH" }}
+ {{- fail (printf "Cannot use .Values.sidecar.datasources.watchClientTimeout with .Values.sidecar.datasources.watchMethod %s" .Values.sidecar.datasources.watchMethod) }}
+ {{- end }}
+ - name: WATCH_CLIENT_TIMEOUT
+ value: "{{ .Values.sidecar.datasources.watchClientTimeout }}"
+ {{- end }}
+ {{- with .Values.sidecar.livenessProbe }}
+ livenessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.readinessProbe }}
+ readinessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.resources }}
+ resources:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.securityContext }}
+ securityContext:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ volumeMounts:
+ - name: sc-datasources-volume
+ mountPath: "/etc/grafana/provisioning/datasources"
+{{- end}}
+{{- if .Values.sidecar.notifiers.enabled }}
+ - name: {{ template "grafana.name" . }}-sc-notifiers
+ {{- if .Values.sidecar.image.sha }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}"
+ {{- else }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}"
+ {{- end }}
+ imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }}
+ env:
+ {{- range $key, $value := .Values.sidecar.notifiers.env }}
+ - name: "{{ $key }}"
+ value: "{{ $value }}"
+ {{- end }}
+ {{- if .Values.sidecar.notifiers.ignoreAlreadyProcessed }}
+ - name: IGNORE_ALREADY_PROCESSED
+ value: "true"
+ {{- end }}
+ - name: METHOD
+ value: {{ .Values.sidecar.notifiers.watchMethod }}
+ - name: LABEL
+ value: "{{ .Values.sidecar.notifiers.label }}"
+ {{- if .Values.sidecar.notifiers.labelValue }}
+ - name: LABEL_VALUE
+ value: {{ quote .Values.sidecar.notifiers.labelValue }}
+ {{- end }}
+ {{- if or .Values.sidecar.logLevel .Values.sidecar.notifiers.logLevel }}
+ - name: LOG_LEVEL
+ value: {{ default .Values.sidecar.logLevel .Values.sidecar.notifiers.logLevel }}
+ {{- end }}
+ - name: FOLDER
+ value: "/etc/grafana/provisioning/notifiers"
+ - name: RESOURCE
+ value: {{ quote .Values.sidecar.notifiers.resource }}
+ {{- if .Values.sidecar.enableUniqueFilenames }}
+ - name: UNIQUE_FILENAMES
+ value: "{{ .Values.sidecar.enableUniqueFilenames }}"
+ {{- end }}
+ {{- if .Values.sidecar.notifiers.searchNamespace }}
+ - name: NAMESPACE
+ value: "{{ tpl (.Values.sidecar.notifiers.searchNamespace | join ",") . }}"
+ {{- end }}
+ {{- if .Values.sidecar.skipTlsVerify }}
+ - name: SKIP_TLS_VERIFY
+ value: "{{ .Values.sidecar.skipTlsVerify }}"
+ {{- end }}
+ {{- if .Values.sidecar.notifiers.script }}
+ - name: SCRIPT
+ value: "{{ .Values.sidecar.notifiers.script }}"
+ {{- end }}
+ {{- if and (not .Values.env.GF_SECURITY_ADMIN_USER) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
+ - name: REQ_USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }}
+ key: {{ .Values.admin.userKey | default "admin-user" }}
+ {{- end }}
+ {{- if and (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
+ - name: REQ_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }}
+ key: {{ .Values.admin.passwordKey | default "admin-password" }}
+ {{- end }}
+ {{- if not .Values.sidecar.notifiers.skipReload }}
+ - name: REQ_URL
+ value: {{ .Values.sidecar.notifiers.reloadURL }}
+ - name: REQ_METHOD
+ value: POST
+ {{- end }}
+ {{- if .Values.sidecar.notifiers.watchServerTimeout }}
+ {{- if ne .Values.sidecar.notifiers.watchMethod "WATCH" }}
+ {{- fail (printf "Cannot use .Values.sidecar.notifiers.watchServerTimeout with .Values.sidecar.notifiers.watchMethod %s" .Values.sidecar.notifiers.watchMethod) }}
+ {{- end }}
+ - name: WATCH_SERVER_TIMEOUT
+ value: "{{ .Values.sidecar.notifiers.watchServerTimeout }}"
+ {{- end }}
+ {{- if .Values.sidecar.notifiers.watchClientTimeout }}
+ {{- if ne .Values.sidecar.notifiers.watchMethod "WATCH" }}
+ {{- fail (printf "Cannot use .Values.sidecar.notifiers.watchClientTimeout with .Values.sidecar.notifiers.watchMethod %s" .Values.sidecar.notifiers.watchMethod) }}
+ {{- end }}
+ - name: WATCH_CLIENT_TIMEOUT
+ value: "{{ .Values.sidecar.notifiers.watchClientTimeout }}"
+ {{- end }}
+ {{- with .Values.sidecar.livenessProbe }}
+ livenessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.readinessProbe }}
+ readinessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.resources }}
+ resources:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.securityContext }}
+ securityContext:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ volumeMounts:
+ - name: sc-notifiers-volume
+ mountPath: "/etc/grafana/provisioning/notifiers"
+{{- end}}
+{{- if .Values.sidecar.plugins.enabled }}
+ - name: {{ template "grafana.name" . }}-sc-plugins
+ {{- if .Values.sidecar.image.sha }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}"
+ {{- else }}
+ image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}"
+ {{- end }}
+ imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }}
+ env:
+ {{- range $key, $value := .Values.sidecar.plugins.env }}
+ - name: "{{ $key }}"
+ value: "{{ $value }}"
+ {{- end }}
+ {{- if .Values.sidecar.plugins.ignoreAlreadyProcessed }}
+ - name: IGNORE_ALREADY_PROCESSED
+ value: "true"
+ {{- end }}
+ - name: METHOD
+ value: {{ .Values.sidecar.plugins.watchMethod }}
+ - name: LABEL
+ value: "{{ .Values.sidecar.plugins.label }}"
+ {{- if .Values.sidecar.plugins.labelValue }}
+ - name: LABEL_VALUE
+ value: {{ quote .Values.sidecar.plugins.labelValue }}
+ {{- end }}
+ {{- if or .Values.sidecar.logLevel .Values.sidecar.plugins.logLevel }}
+ - name: LOG_LEVEL
+ value: {{ default .Values.sidecar.logLevel .Values.sidecar.plugins.logLevel }}
+ {{- end }}
+ - name: FOLDER
+ value: "/etc/grafana/provisioning/plugins"
+ - name: RESOURCE
+ value: {{ quote .Values.sidecar.plugins.resource }}
+ {{- if .Values.sidecar.enableUniqueFilenames }}
+ - name: UNIQUE_FILENAMES
+ value: "{{ .Values.sidecar.enableUniqueFilenames }}"
+ {{- end }}
+ {{- if .Values.sidecar.plugins.searchNamespace }}
+ - name: NAMESPACE
+ value: "{{ tpl (.Values.sidecar.plugins.searchNamespace | join ",") . }}"
+ {{- end }}
+ {{- if .Values.sidecar.plugins.script }}
+ - name: SCRIPT
+ value: "{{ .Values.sidecar.plugins.script }}"
+ {{- end }}
+ {{- if .Values.sidecar.skipTlsVerify }}
+ - name: SKIP_TLS_VERIFY
+ value: "{{ .Values.sidecar.skipTlsVerify }}"
+ {{- end }}
+ {{- if and (not .Values.env.GF_SECURITY_ADMIN_USER) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
+ - name: REQ_USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }}
+ key: {{ .Values.admin.userKey | default "admin-user" }}
+ {{- end }}
+ {{- if and (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
+ - name: REQ_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }}
+ key: {{ .Values.admin.passwordKey | default "admin-password" }}
+ {{- end }}
+ {{- if not .Values.sidecar.plugins.skipReload }}
+ - name: REQ_URL
+ value: {{ .Values.sidecar.plugins.reloadURL }}
+ - name: REQ_METHOD
+ value: POST
+ {{- end }}
+ {{- if .Values.sidecar.plugins.watchServerTimeout }}
+ {{- if ne .Values.sidecar.plugins.watchMethod "WATCH" }}
+ {{- fail (printf "Cannot use .Values.sidecar.plugins.watchServerTimeout with .Values.sidecar.plugins.watchMethod %s" .Values.sidecar.plugins.watchMethod) }}
+ {{- end }}
+ - name: WATCH_SERVER_TIMEOUT
+ value: "{{ .Values.sidecar.plugins.watchServerTimeout }}"
+ {{- end }}
+ {{- if .Values.sidecar.plugins.watchClientTimeout }}
+ {{- if ne .Values.sidecar.plugins.watchMethod "WATCH" }}
+ {{- fail (printf "Cannot use .Values.sidecar.plugins.watchClientTimeout with .Values.sidecar.plugins.watchMethod %s" .Values.sidecar.plugins.watchMethod) }}
+ {{- end }}
+ - name: WATCH_CLIENT_TIMEOUT
+ value: "{{ .Values.sidecar.plugins.watchClientTimeout }}"
+ {{- end }}
+ {{- with .Values.sidecar.livenessProbe }}
+ livenessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.readinessProbe }}
+ readinessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.resources }}
+ resources:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.sidecar.securityContext }}
+ securityContext:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ volumeMounts:
+ - name: sc-plugins-volume
+ mountPath: "/etc/grafana/provisioning/plugins"
+{{- end}}
+ - name: {{ .Chart.Name }}
+ {{- if .Values.image.sha }}
+ image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}@sha256:{{ .Values.image.sha }}"
+ {{- else }}
+ image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+ {{- end }}
+ imagePullPolicy: {{ .Values.image.pullPolicy }}
+ {{- if .Values.command }}
+ command:
+ {{- range .Values.command }}
+ - {{ . }}
+ {{- end }}
+ {{- end}}
+ {{- with .Values.containerSecurityContext }}
+ securityContext:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ volumeMounts:
+ - name: config
+ mountPath: "/etc/grafana/grafana.ini"
+ subPath: grafana.ini
+ {{- if .Values.ldap.enabled }}
+ - name: ldap
+ mountPath: "/etc/grafana/ldap.toml"
+ subPath: ldap.toml
+ {{- end }}
+ {{- $root := . }}
+ {{- range .Values.extraConfigmapMounts }}
+ - name: {{ tpl .name $root }}
+ mountPath: {{ tpl .mountPath $root }}
+ subPath: {{ (tpl .subPath $root) | default "" }}
+ readOnly: {{ .readOnly }}
+ {{- end }}
+ - name: storage
+ mountPath: "/var/lib/grafana"
+{{- if .Values.persistence.subPath }}
+ subPath: {{ tpl .Values.persistence.subPath . }}
+{{- end }}
+{{- if .Values.dashboards }}
+{{- range $provider, $dashboards := .Values.dashboards }}
+{{- range $key, $value := $dashboards }}
+{{- if (or (hasKey $value "json") (hasKey $value "file")) }}
+ - name: dashboards-{{ $provider }}
+ mountPath: "/var/lib/grafana/dashboards/{{ $provider }}/{{ $key }}.json"
+ subPath: "{{ $key }}.json"
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end -}}
+{{- if .Values.dashboardsConfigMaps }}
+{{- range (keys .Values.dashboardsConfigMaps | sortAlpha) }}
+ - name: dashboards-{{ . }}
+ mountPath: "/var/lib/grafana/dashboards/{{ . }}"
+{{- end }}
+{{- end }}
+{{- if .Values.datasources }}
+{{- range (keys .Values.datasources | sortAlpha) }}
+ - name: config
+ mountPath: "/etc/grafana/provisioning/datasources/{{ . }}"
+ subPath: {{ . | quote }}
+{{- end }}
+{{- end }}
+{{- if .Values.notifiers }}
+{{- range (keys .Values.notifiers | sortAlpha) }}
+ - name: config
+ mountPath: "/etc/grafana/provisioning/notifiers/{{ . }}"
+ subPath: {{ . | quote }}
+{{- end }}
+{{- end }}
+{{- if .Values.alerting }}
+{{- range (keys .Values.alerting | sortAlpha) }}
+ - name: config
+ mountPath: "/etc/grafana/provisioning/alerting/{{ . }}"
+ subPath: {{ . | quote }}
+{{- end }}
+{{- end }}
+{{- if .Values.dashboardProviders }}
+{{- range (keys .Values.dashboardProviders | sortAlpha) }}
+ - name: config
+ mountPath: "/etc/grafana/provisioning/dashboards/{{ . }}"
+ subPath: {{ . | quote }}
+{{- end }}
+{{- end }}
+{{- with .Values.sidecar.alerts.enabled }}
+ - name: sc-alerts-volume
+ mountPath: "/etc/grafana/provisioning/alerting"
+{{- end}}
+{{- if .Values.sidecar.dashboards.enabled }}
+ - name: sc-dashboard-volume
+ mountPath: {{ .Values.sidecar.dashboards.folder | quote }}
+{{ if .Values.sidecar.dashboards.SCProvider }}
+ - name: sc-dashboard-provider
+ mountPath: "/etc/grafana/provisioning/dashboards/sc-dashboardproviders.yaml"
+ subPath: provider.yaml
+{{- end}}
+{{- end}}
+{{- if .Values.sidecar.datasources.enabled }}
+ - name: sc-datasources-volume
+ mountPath: "/etc/grafana/provisioning/datasources"
+{{- end}}
+{{- if .Values.sidecar.plugins.enabled }}
+ - name: sc-plugins-volume
+ mountPath: "/etc/grafana/provisioning/plugins"
+{{- end}}
+{{- if .Values.sidecar.notifiers.enabled }}
+ - name: sc-notifiers-volume
+ mountPath: "/etc/grafana/provisioning/notifiers"
+{{- end}}
+ {{- range .Values.extraSecretMounts }}
+ - name: {{ .name }}
+ mountPath: {{ .mountPath }}
+ readOnly: {{ .readOnly }}
+ subPath: {{ .subPath | default "" }}
+ {{- end }}
+ {{- range .Values.extraVolumeMounts }}
+ - name: {{ .name }}
+ mountPath: {{ .mountPath }}
+ subPath: {{ .subPath | default "" }}
+ readOnly: {{ .readOnly }}
+ {{- end }}
+ {{- range .Values.extraEmptyDirMounts }}
+ - name: {{ .name }}
+ mountPath: {{ .mountPath }}
+ {{- end }}
+ ports:
+ - name: {{ .Values.podPortName }}
+ containerPort: {{ .Values.service.targetPort }}
+ protocol: TCP
+ env:
+ {{- if and (not .Values.env.GF_SECURITY_ADMIN_USER) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
+ - name: GF_SECURITY_ADMIN_USER
+ valueFrom:
+ secretKeyRef:
+ name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }}
+ key: {{ .Values.admin.userKey | default "admin-user" }}
+ {{- end }}
+ {{- if and (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
+ - name: GF_SECURITY_ADMIN_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }}
+ key: {{ .Values.admin.passwordKey | default "admin-password" }}
+ {{- end }}
+ {{- if .Values.plugins }}
+ - name: GF_INSTALL_PLUGINS
+ valueFrom:
+ configMapKeyRef:
+ name: {{ template "grafana.fullname" . }}
+ key: plugins
+ {{- end }}
+ {{- if .Values.smtp.existingSecret }}
+ - name: GF_SMTP_USER
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.smtp.existingSecret }}
+ key: {{ .Values.smtp.userKey | default "user" }}
+ - name: GF_SMTP_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.smtp.existingSecret }}
+ key: {{ .Values.smtp.passwordKey | default "password" }}
+ {{- end }}
+ {{- if .Values.imageRenderer.enabled }}
+ - name: GF_RENDERING_SERVER_URL
+ value: http://{{ template "grafana.fullname" . }}-image-renderer.{{ template "grafana.namespace" . }}:{{ .Values.imageRenderer.service.port }}/render
+ - name: GF_RENDERING_CALLBACK_URL
+ value: {{ .Values.imageRenderer.grafanaProtocol }}://{{ template "grafana.fullname" . }}.{{ template "grafana.namespace" . }}:{{ .Values.service.port }}/{{ .Values.imageRenderer.grafanaSubPath }}
+ {{- end }}
+ - name: GF_PATHS_DATA
+ value: {{ (get .Values "grafana.ini").paths.data }}
+ - name: GF_PATHS_LOGS
+ value: {{ (get .Values "grafana.ini").paths.logs }}
+ - name: GF_PATHS_PLUGINS
+ value: {{ (get .Values "grafana.ini").paths.plugins }}
+ - name: GF_PATHS_PROVISIONING
+ value: {{ (get .Values "grafana.ini").paths.provisioning }}
+ {{- range $key, $value := .Values.envValueFrom }}
+ - name: {{ $key | quote }}
+ valueFrom:
+{{ tpl (toYaml $value) $ | indent 10 }}
+ {{- end }}
+{{- range $key, $value := .Values.env }}
+ - name: "{{ tpl $key $ }}"
+ value: "{{ tpl (print $value) $ }}"
+{{- end }}
+ {{- if or .Values.envFromSecret (or .Values.envRenderSecret .Values.envFromSecrets) .Values.envFromConfigMaps }}
+ envFrom:
+ {{- if .Values.envFromSecret }}
+ - secretRef:
+ name: {{ tpl .Values.envFromSecret . }}
+ {{- end }}
+ {{- if .Values.envRenderSecret }}
+ - secretRef:
+ name: {{ template "grafana.fullname" . }}-env
+ {{- end }}
+ {{- range .Values.envFromSecrets }}
+ - secretRef:
+ name: {{ tpl .name $ }}
+ optional: {{ .optional | default false }}
+ {{- end }}
+ {{- range .Values.envFromConfigMaps }}
+ - configMapRef:
+ name: {{ tpl .name $ }}
+ optional: {{ .optional | default false }}
+ {{- end }}
+ {{- end }}
+ {{- with .Values.livenessProbe }}
+ livenessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+ {{- with .Values.readinessProbe }}
+ readinessProbe:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+{{- if .Values.lifecycleHooks }}
+ lifecycle: {{ tpl (.Values.lifecycleHooks | toYaml) . | nindent 6 }}
+{{- end }}
+ {{- with .Values.resources }}
+ resources:
+ {{- toYaml . | nindent 6 }}
+ {{- end }}
+{{- with .Values.extraContainers }}
+{{ tpl . $ | indent 2 }}
+{{- end }}
+{{- with .Values.nodeSelector }}
+nodeSelector:
+ {{- toYaml . | nindent 2 }}
+{{- end }}
+{{- $root := . }}
+{{- with .Values.affinity }}
+affinity:
+{{ tpl (toYaml .) $root | indent 2 }}
+{{- end }}
+{{- with .Values.topologySpreadConstraints }}
+topologySpreadConstraints:
+ {{- toYaml . | nindent 2 }}
+{{- end }}
+{{- with .Values.tolerations }}
+tolerations:
+ {{- toYaml . | nindent 2 }}
+{{- end }}
+volumes:
+ - name: config
+ configMap:
+ name: {{ template "grafana.fullname" . }}
+{{- $root := . }}
+{{- range .Values.extraConfigmapMounts }}
+ - name: {{ tpl .name $root }}
+ configMap:
+ name: {{ tpl .configMap $root }}
+ {{- if .items }}
+ items: {{ toYaml .items | nindent 6 }}
+ {{- end }}
+{{- end }}
+ {{- if .Values.dashboards }}
+ {{- range (keys .Values.dashboards | sortAlpha) }}
+ - name: dashboards-{{ . }}
+ configMap:
+ name: {{ template "grafana.fullname" $ }}-dashboards-{{ . }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.dashboardsConfigMaps }}
+ {{ $root := . }}
+ {{- range $provider, $name := .Values.dashboardsConfigMaps }}
+ - name: dashboards-{{ $provider }}
+ configMap:
+ name: {{ tpl $name $root }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.ldap.enabled }}
+ - name: ldap
+ secret:
+ {{- if .Values.ldap.existingSecret }}
+ secretName: {{ .Values.ldap.existingSecret }}
+ {{- else }}
+ secretName: {{ template "grafana.fullname" . }}
+ {{- end }}
+ items:
+ - key: ldap-toml
+ path: ldap.toml
+ {{- end }}
+{{- if and .Values.persistence.enabled (eq .Values.persistence.type "pvc") }}
+ - name: storage
+ persistentVolumeClaim:
+ claimName: {{ tpl (.Values.persistence.existingClaim | default (include "grafana.fullname" .)) . }}
+{{- else if and .Values.persistence.enabled (eq .Values.persistence.type "statefulset") }}
+# nothing
+{{- else }}
+ - name: storage
+{{- if .Values.persistence.inMemory.enabled }}
+ emptyDir:
+ medium: Memory
+{{- if .Values.persistence.inMemory.sizeLimit }}
+ sizeLimit: {{ .Values.persistence.inMemory.sizeLimit }}
+{{- end -}}
+{{- else }}
+ emptyDir: {}
+{{- end -}}
+{{- end -}}
+{{- if .Values.sidecar.alerts.enabled }}
+ - name: sc-alerts-volume
+{{- if .Values.sidecar.alerts.sizeLimit }}
+ emptyDir:
+ sizeLimit: {{ .Values.sidecar.alerts.sizeLimit }}
+{{- else }}
+ emptyDir: {}
+{{- end -}}
+{{- end -}}
+{{- if .Values.sidecar.dashboards.enabled }}
+ - name: sc-dashboard-volume
+{{- if .Values.sidecar.dashboards.sizeLimit }}
+ emptyDir:
+ sizeLimit: {{ .Values.sidecar.dashboards.sizeLimit }}
+{{- else }}
+ emptyDir: {}
+{{- end -}}
+{{- if .Values.sidecar.dashboards.SCProvider }}
+ - name: sc-dashboard-provider
+ configMap:
+ name: {{ template "grafana.fullname" . }}-config-dashboards
+{{- end }}
+{{- end }}
+{{- if .Values.sidecar.datasources.enabled }}
+ - name: sc-datasources-volume
+{{- if .Values.sidecar.datasources.sizeLimit }}
+ emptyDir:
+ sizeLimit: {{ .Values.sidecar.datasources.sizeLimit }}
+{{- else }}
+ emptyDir: {}
+{{- end -}}
+{{- end -}}
+{{- if .Values.sidecar.plugins.enabled }}
+ - name: sc-plugins-volume
+{{- if .Values.sidecar.plugins.sizeLimit }}
+ emptyDir:
+ sizeLimit: {{ .Values.sidecar.plugins.sizeLimit }}
+{{- else }}
+ emptyDir: {}
+{{- end -}}
+{{- end -}}
+{{- if .Values.sidecar.notifiers.enabled }}
+ - name: sc-notifiers-volume
+{{- if .Values.sidecar.notifiers.sizeLimit }}
+ emptyDir:
+ sizeLimit: {{ .Values.sidecar.notifiers.sizeLimit }}
+{{- else }}
+ emptyDir: {}
+{{- end -}}
+{{- end -}}
+{{- range .Values.extraSecretMounts }}
+{{- if .secretName }}
+ - name: {{ .name }}
+ secret:
+ secretName: {{ .secretName }}
+ defaultMode: {{ .defaultMode }}
+ {{- if .items }}
+ items: {{ toYaml .items | nindent 6 }}
+ {{- end }}
+{{- else if .projected }}
+ - name: {{ .name }}
+ projected: {{- toYaml .projected | nindent 6 }}
+{{- else if .csi }}
+ - name: {{ .name }}
+ csi: {{- toYaml .csi | nindent 6 }}
+{{- end }}
+{{- end }}
+{{- range .Values.extraVolumeMounts }}
+ - name: {{ .name }}
+ {{- if .existingClaim }}
+ persistentVolumeClaim:
+ claimName: {{ .existingClaim }}
+ {{- else if .hostPath }}
+ hostPath:
+ path: {{ .hostPath }}
+ {{- else if .csi }}
+ csi:
+ data:
+ {{ toYaml .data | nindent 6 }}
+ {{- else }}
+ emptyDir: {}
+ {{- end }}
+{{- end }}
+{{- range .Values.extraEmptyDirMounts }}
+ - name: {{ .name }}
+ emptyDir: {}
+{{- end -}}
+{{- if .Values.extraContainerVolumes }}
+{{ tpl (toYaml .Values.extraContainerVolumes) . | indent 2 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/clusterrole.yaml b/kube-prometheus-stack/charts/grafana/templates/clusterrole.yaml
new file mode 100644
index 00000000..154658b5
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/clusterrole.yaml
@@ -0,0 +1,25 @@
+{{- if and .Values.rbac.create (not .Values.rbac.namespaced) (not .Values.rbac.useExistingRole) }}
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+ name: {{ template "grafana.fullname" . }}-clusterrole
+{{- if or .Values.sidecar.dashboards.enabled (or .Values.rbac.extraClusterRoleRules (or .Values.sidecar.datasources.enabled .Values.sidecar.plugins.enabled)) }}
+rules:
+{{- if or .Values.sidecar.dashboards.enabled (or .Values.sidecar.datasources.enabled .Values.sidecar.plugins.enabled) }}
+- apiGroups: [""] # "" indicates the core API group
+ resources: ["configmaps", "secrets"]
+ verbs: ["get", "watch", "list"]
+{{- end}}
+{{- with .Values.rbac.extraClusterRoleRules }}
+{{ toYaml . | indent 0 }}
+{{- end}}
+{{- else }}
+rules: []
+{{- end}}
+{{- end}}
diff --git a/kube-prometheus-stack/charts/grafana/templates/clusterrolebinding.yaml b/kube-prometheus-stack/charts/grafana/templates/clusterrolebinding.yaml
new file mode 100644
index 00000000..4accbfac
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/clusterrolebinding.yaml
@@ -0,0 +1,24 @@
+{{- if and .Values.rbac.create (not .Values.rbac.namespaced) }}
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: {{ template "grafana.fullname" . }}-clusterrolebinding
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+subjects:
+ - kind: ServiceAccount
+ name: {{ template "grafana.serviceAccountName" . }}
+ namespace: {{ template "grafana.namespace" . }}
+roleRef:
+ kind: ClusterRole
+{{- if (not .Values.rbac.useExistingRole) }}
+ name: {{ template "grafana.fullname" . }}-clusterrole
+{{- else }}
+ name: {{ .Values.rbac.useExistingRole }}
+{{- end }}
+ apiGroup: rbac.authorization.k8s.io
+{{- end -}}
diff --git a/kube-prometheus-stack/charts/grafana/templates/configmap-dashboard-provider.yaml b/kube-prometheus-stack/charts/grafana/templates/configmap-dashboard-provider.yaml
new file mode 100644
index 00000000..65d73858
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/configmap-dashboard-provider.yaml
@@ -0,0 +1,29 @@
+{{- if .Values.sidecar.dashboards.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+ name: {{ template "grafana.fullname" . }}-config-dashboards
+ namespace: {{ template "grafana.namespace" . }}
+data:
+ provider.yaml: |-
+ apiVersion: 1
+ providers:
+ - name: '{{ .Values.sidecar.dashboards.provider.name }}'
+ orgId: {{ .Values.sidecar.dashboards.provider.orgid }}
+ {{- if not .Values.sidecar.dashboards.provider.foldersFromFilesStructure }}
+ folder: '{{ .Values.sidecar.dashboards.provider.folder }}'
+ {{- end}}
+ type: {{ .Values.sidecar.dashboards.provider.type }}
+ disableDeletion: {{ .Values.sidecar.dashboards.provider.disableDelete }}
+ allowUiUpdates: {{ .Values.sidecar.dashboards.provider.allowUiUpdates }}
+ updateIntervalSeconds: {{ .Values.sidecar.dashboards.provider.updateIntervalSeconds | default 30 }}
+ options:
+ foldersFromFilesStructure: {{ .Values.sidecar.dashboards.provider.foldersFromFilesStructure }}
+ path: {{ .Values.sidecar.dashboards.folder }}{{- with .Values.sidecar.dashboards.defaultFolderName }}/{{ . }}{{- end }}
+{{- end}}
diff --git a/kube-prometheus-stack/charts/grafana/templates/configmap.yaml b/kube-prometheus-stack/charts/grafana/templates/configmap.yaml
new file mode 100644
index 00000000..87460cd3
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/configmap.yaml
@@ -0,0 +1,117 @@
+{{- if .Values.createConfigmap }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+data:
+{{- if .Values.plugins }}
+ plugins: {{ join "," .Values.plugins }}
+{{- end }}
+ grafana.ini: |
+{{- range $elem, $elemVal := index .Values "grafana.ini" }}
+ {{- if not (kindIs "map" $elemVal) }}
+ {{- if kindIs "invalid" $elemVal }}
+ {{ $elem }} =
+ {{- else if kindIs "string" $elemVal }}
+ {{ $elem }} = {{ tpl $elemVal $ }}
+ {{- else }}
+ {{ $elem }} = {{ $elemVal }}
+ {{- end }}
+ {{- end }}
+{{- end }}
+{{- range $key, $value := index .Values "grafana.ini" }}
+ {{- if kindIs "map" $value }}
+ [{{ $key }}]
+ {{- range $elem, $elemVal := $value }}
+ {{- if kindIs "invalid" $elemVal }}
+ {{ $elem }} =
+ {{- else if kindIs "string" $elemVal }}
+ {{ $elem }} = {{ tpl $elemVal $ }}
+ {{- else }}
+ {{ $elem }} = {{ $elemVal }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+{{- end }}
+
+{{- if .Values.datasources }}
+{{ $root := . }}
+ {{- range $key, $value := .Values.datasources }}
+ {{ $key }}: |
+{{ tpl (toYaml $value | indent 4) $root }}
+ {{- end -}}
+{{- end -}}
+
+{{- if .Values.notifiers }}
+ {{- range $key, $value := .Values.notifiers }}
+ {{ $key }}: |
+{{ toYaml $value | indent 4 }}
+ {{- end -}}
+{{- end -}}
+
+{{- if .Values.alerting }}
+{{ $root := . }}
+ {{- range $key, $value := .Values.alerting }}
+ {{ $key }}: |
+{{ tpl (toYaml $value | indent 4) $root }}
+ {{- end -}}
+{{- end -}}
+
+{{- if .Values.dashboardProviders }}
+ {{- range $key, $value := .Values.dashboardProviders }}
+ {{ $key }}: |
+{{ toYaml $value | indent 4 }}
+ {{- end -}}
+{{- end -}}
+
+{{- if .Values.dashboards }}
+ download_dashboards.sh: |
+ #!/usr/bin/env sh
+ set -euf
+ {{- if .Values.dashboardProviders }}
+ {{- range $key, $value := .Values.dashboardProviders }}
+ {{- range $value.providers }}
+ mkdir -p {{ .options.path }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{ $dashboardProviders := .Values.dashboardProviders }}
+ {{- range $provider, $dashboards := .Values.dashboards }}
+ {{- range $key, $value := $dashboards }}
+ {{- if (or (hasKey $value "gnetId") (hasKey $value "url")) }}
+ curl -skf \
+ --connect-timeout 60 \
+ --max-time 60 \
+ {{- if not $value.b64content }}
+ -H "Accept: application/json" \
+ {{- if $value.token }}
+ -H "Authorization: token {{ $value.token }}" \
+ {{- end }}
+ {{- if $value.bearerToken }}
+ -H "Authorization: Bearer {{ $value.bearerToken }}" \
+ {{- end }}
+ {{- if $value.gitlabToken }}
+ -H "PRIVATE-TOKEN: {{ $value.gitlabToken }}" \
+ {{- end }}
+ -H "Content-Type: application/json;charset=UTF-8" \
+ {{ end }}
+ {{- $dpPath := "" -}}
+ {{- range $kd := (index $dashboardProviders "dashboardproviders.yaml").providers -}}
+ {{- if eq $kd.name $provider -}}
+ {{- $dpPath = $kd.options.path -}}
+ {{- end -}}
+ {{- end -}}
+ {{- if $value.url -}}"{{ $value.url }}"{{- else -}}"https://grafana.com/api/dashboards/{{ $value.gnetId }}/revisions/{{- if $value.revision -}}{{ $value.revision }}{{- else -}}1{{- end -}}/download"{{- end -}}{{ if $value.datasource }} | sed '/-- .* --/! s/"datasource":.*,/"datasource": "{{ $value.datasource }}",/g'{{ end }}{{- if $value.b64content -}} | base64 -d {{- end -}} \
+ > "{{- if $dpPath -}}{{ $dpPath }}{{- else -}}/var/lib/grafana/dashboards/{{ $provider }}{{- end -}}/{{ $key }}.json"
+ {{- end }}
+ {{- end -}}
+ {{- end }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/dashboards-json-configmap.yaml b/kube-prometheus-stack/charts/grafana/templates/dashboards-json-configmap.yaml
new file mode 100644
index 00000000..59e0be64
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/dashboards-json-configmap.yaml
@@ -0,0 +1,35 @@
+{{- if .Values.dashboards }}
+{{ $files := .Files }}
+{{- range $provider, $dashboards := .Values.dashboards }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ template "grafana.fullname" $ }}-dashboards-{{ $provider }}
+ namespace: {{ template "grafana.namespace" $ }}
+ labels:
+ {{- include "grafana.labels" $ | nindent 4 }}
+ dashboard-provider: {{ $provider }}
+{{- if $dashboards }}
+data:
+{{- $dashboardFound := false }}
+{{- range $key, $value := $dashboards }}
+{{- if (or (hasKey $value "json") (hasKey $value "file")) }}
+{{- $dashboardFound = true }}
+{{ print $key | indent 2 }}.json:
+{{- if hasKey $value "json" }}
+ |-
+{{ $value.json | indent 6 }}
+{{- end }}
+{{- if hasKey $value "file" }}
+{{ toYaml ( $files.Get $value.file ) | indent 4}}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- if not $dashboardFound }}
+ {}
+{{- end }}
+{{- end }}
+---
+{{- end }}
+
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/deployment.yaml b/kube-prometheus-stack/charts/grafana/templates/deployment.yaml
new file mode 100644
index 00000000..fee9c335
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/deployment.yaml
@@ -0,0 +1,50 @@
+{{ if (and (not .Values.useStatefulSet) (or (not .Values.persistence.enabled) (eq .Values.persistence.type "pvc"))) }}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- if .Values.labels }}
+{{ toYaml .Values.labels | indent 4 }}
+{{- end }}
+{{- with .Values.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+ {{- if and (not .Values.autoscaling.enabled) (.Values.replicas) }}
+ replicas: {{ .Values.replicas }}
+ {{- end }}
+ revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
+ selector:
+ matchLabels:
+ {{- include "grafana.selectorLabels" . | nindent 6 }}
+{{- with .Values.deploymentStrategy }}
+ strategy:
+{{ toYaml . | trim | indent 4 }}
+{{- end }}
+ template:
+ metadata:
+ labels:
+ {{- include "grafana.selectorLabels" . | nindent 8 }}
+{{- with .Values.podLabels }}
+{{ toYaml . | indent 8 }}
+{{- end }}
+ annotations:
+ checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
+ checksum/dashboards-json-config: {{ include (print $.Template.BasePath "/dashboards-json-configmap.yaml") . | sha256sum }}
+ checksum/sc-dashboard-provider-config: {{ include (print $.Template.BasePath "/configmap-dashboard-provider.yaml") . | sha256sum }}
+{{- if and (or (and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD)) (and .Values.ldap.enabled (not .Values.ldap.existingSecret))) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
+ checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
+{{- end }}
+{{- if .Values.envRenderSecret }}
+ checksum/secret-env: {{ include (print $.Template.BasePath "/secret-env.yaml") . | sha256sum }}
+{{- end }}
+{{- with .Values.podAnnotations }}
+{{ toYaml . | indent 8 }}
+{{- end }}
+ spec:
+ {{- include "grafana.pod" . | indent 6 }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/extra-manifests.yaml b/kube-prometheus-stack/charts/grafana/templates/extra-manifests.yaml
new file mode 100644
index 00000000..a9bb3b6b
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/extra-manifests.yaml
@@ -0,0 +1,4 @@
+{{ range .Values.extraObjects }}
+---
+{{ tpl (toYaml .) $ }}
+{{ end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/headless-service.yaml b/kube-prometheus-stack/charts/grafana/templates/headless-service.yaml
new file mode 100644
index 00000000..b5faddcf
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/headless-service.yaml
@@ -0,0 +1,22 @@
+{{- if or .Values.headlessService (and .Values.persistence.enabled (not .Values.persistence.existingClaim) (eq .Values.persistence.type "statefulset"))}}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "grafana.fullname" . }}-headless
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+ clusterIP: None
+ selector:
+ {{- include "grafana.selectorLabels" . | nindent 4 }}
+ type: ClusterIP
+ ports:
+ - protocol: TCP
+ port: 3000
+ targetPort: {{ .Values.service.targetPort }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/hpa.yaml b/kube-prometheus-stack/charts/grafana/templates/hpa.yaml
new file mode 100644
index 00000000..05723974
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/hpa.yaml
@@ -0,0 +1,21 @@
+{{- if .Values.autoscaling.enabled }}
+apiVersion: autoscaling/v2beta1
+kind: HorizontalPodAutoscaler
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ app.kubernetes.io/name: {{ template "grafana.name" . }}
+ helm.sh/chart: {{ template "grafana.chart" . }}
+ app.kubernetes.io/managed-by: {{ .Release.Service }}
+ app.kubernetes.io/instance: {{ .Release.Name }}
+spec:
+ scaleTargetRef:
+ apiVersion: apps/v1
+ kind: Deployment
+ name: {{ template "grafana.fullname" . }}
+ minReplicas: {{ .Values.autoscaling.minReplicas }}
+ maxReplicas: {{ .Values.autoscaling.maxReplicas }}
+ metrics:
+{{ toYaml .Values.autoscaling.metrics | indent 4 }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/image-renderer-deployment.yaml b/kube-prometheus-stack/charts/grafana/templates/image-renderer-deployment.yaml
new file mode 100644
index 00000000..c558a86a
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/image-renderer-deployment.yaml
@@ -0,0 +1,121 @@
+{{ if .Values.imageRenderer.enabled }}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ template "grafana.fullname" . }}-image-renderer
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.imageRenderer.labels" . | nindent 4 }}
+{{- if .Values.imageRenderer.labels }}
+{{ toYaml .Values.imageRenderer.labels | indent 4 }}
+{{- end }}
+{{- with .Values.imageRenderer.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+ replicas: {{ .Values.imageRenderer.replicas }}
+ revisionHistoryLimit: {{ .Values.imageRenderer.revisionHistoryLimit }}
+ selector:
+ matchLabels:
+ {{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }}
+{{- with .Values.imageRenderer.deploymentStrategy }}
+ strategy:
+{{ toYaml . | trim | indent 4 }}
+{{- end }}
+ template:
+ metadata:
+ labels:
+ {{- include "grafana.imageRenderer.selectorLabels" . | nindent 8 }}
+{{- with .Values.imageRenderer.podLabels }}
+{{ toYaml . | indent 8 }}
+{{- end }}
+ annotations:
+ checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
+{{- with .Values.imageRenderer.podAnnotations }}
+{{ toYaml . | indent 8 }}
+{{- end }}
+ spec:
+
+ {{- if .Values.imageRenderer.schedulerName }}
+ schedulerName: "{{ .Values.imageRenderer.schedulerName }}"
+ {{- end }}
+ {{- if .Values.imageRenderer.serviceAccountName }}
+ serviceAccountName: "{{ .Values.imageRenderer.serviceAccountName }}"
+ {{- end }}
+ {{- if .Values.imageRenderer.securityContext }}
+ securityContext:
+ {{- toYaml .Values.imageRenderer.securityContext | nindent 8 }}
+ {{- end }}
+ {{- if .Values.imageRenderer.hostAliases }}
+ hostAliases:
+ {{- toYaml .Values.imageRenderer.hostAliases | nindent 8 }}
+ {{- end }}
+ {{- if .Values.imageRenderer.priorityClassName }}
+ priorityClassName: {{ .Values.imageRenderer.priorityClassName }}
+ {{- end }}
+ {{- if .Values.imageRenderer.image.pullSecrets }}
+ imagePullSecrets:
+ {{- $root := . }}
+ {{- range .Values.imageRenderer.image.pullSecrets }}
+ - name: {{ tpl . $root }}
+ {{- end}}
+ {{- end }}
+ containers:
+ - name: {{ .Chart.Name }}-image-renderer
+ {{- if .Values.imageRenderer.image.sha }}
+ image: "{{ .Values.imageRenderer.image.repository }}:{{ .Values.imageRenderer.image.tag }}@sha256:{{ .Values.imageRenderer.image.sha }}"
+ {{- else }}
+ image: "{{ .Values.imageRenderer.image.repository }}:{{ .Values.imageRenderer.image.tag }}"
+ {{- end }}
+ imagePullPolicy: {{ .Values.imageRenderer.image.pullPolicy }}
+ {{- if .Values.imageRenderer.command }}
+ command:
+ {{- range .Values.imageRenderer.command }}
+ - {{ . }}
+ {{- end }}
+ {{- end}}
+ ports:
+ - name: {{ .Values.imageRenderer.service.portName }}
+ containerPort: {{ .Values.imageRenderer.service.targetPort }}
+ protocol: TCP
+ livenessProbe:
+ httpGet:
+ path: /
+ port: {{ .Values.imageRenderer.service.portName }}
+ env:
+ - name: HTTP_PORT
+ value: {{ .Values.imageRenderer.service.targetPort | quote }}
+ {{- range $key, $value := .Values.imageRenderer.env }}
+ - name: {{ $key | quote }}
+ value: {{ $value | quote }}
+ {{- end }}
+ securityContext:
+ capabilities:
+ drop: ['all']
+ allowPrivilegeEscalation: false
+ readOnlyRootFilesystem: true
+ volumeMounts:
+ - mountPath: /tmp
+ name: image-renderer-tmpfs
+ {{- with .Values.imageRenderer.resources }}
+ resources:
+{{ toYaml . | indent 12 }}
+ {{- end }}
+ {{- with .Values.imageRenderer.nodeSelector }}
+ nodeSelector:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ {{- $root := . }}
+ {{- with .Values.imageRenderer.affinity }}
+ affinity:
+{{ tpl (toYaml .) $root | indent 8 }}
+ {{- end }}
+ {{- with .Values.imageRenderer.tolerations }}
+ tolerations:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ volumes:
+ - name: image-renderer-tmpfs
+ emptyDir: {}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/image-renderer-network-policy.yaml b/kube-prometheus-stack/charts/grafana/templates/image-renderer-network-policy.yaml
new file mode 100644
index 00000000..0d9bdfe4
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/image-renderer-network-policy.yaml
@@ -0,0 +1,73 @@
+{{- if and (.Values.imageRenderer.enabled) (.Values.imageRenderer.networkPolicy.limitIngress) }}
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: {{ template "grafana.fullname" . }}-image-renderer-ingress
+ namespace: {{ template "grafana.namespace" . }}
+ annotations:
+ comment: Limit image-renderer ingress traffic from grafana
+spec:
+ podSelector:
+ matchLabels:
+ {{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }}
+ {{- if .Values.imageRenderer.podLabels }}
+ {{ toYaml .Values.imageRenderer.podLabels | nindent 6 }}
+ {{- end }}
+
+ policyTypes:
+ - Ingress
+ ingress:
+ - ports:
+ - port: {{ .Values.imageRenderer.service.targetPort }}
+ protocol: TCP
+ from:
+ - namespaceSelector:
+ matchLabels:
+ name: {{ template "grafana.namespace" . }}
+ podSelector:
+ matchLabels:
+ {{- include "grafana.selectorLabels" . | nindent 14 }}
+ {{- if .Values.podLabels }}
+ {{ toYaml .Values.podLabels | nindent 14 }}
+ {{- end }}
+{{ end }}
+
+{{- if and (.Values.imageRenderer.enabled) (.Values.imageRenderer.networkPolicy.limitEgress) }}
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: {{ template "grafana.fullname" . }}-image-renderer-egress
+ namespace: {{ template "grafana.namespace" . }}
+ annotations:
+ comment: Limit image-renderer egress traffic to grafana
+spec:
+ podSelector:
+ matchLabels:
+ {{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }}
+ {{- if .Values.imageRenderer.podLabels }}
+ {{ toYaml .Values.imageRenderer.podLabels | nindent 6 }}
+ {{- end }}
+
+ policyTypes:
+ - Egress
+ egress:
+ # allow dns resolution
+ - ports:
+ - port: 53
+ protocol: UDP
+ - port: 53
+ protocol: TCP
+ # talk only to grafana
+ - ports:
+ - port: {{ .Values.service.port }}
+ protocol: TCP
+ to:
+ - podSelector:
+ matchLabels:
+ {{- include "grafana.selectorLabels" . | nindent 14 }}
+ {{- if .Values.podLabels }}
+ {{ toYaml .Values.podLabels | nindent 14 }}
+ {{- end }}
+{{ end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/image-renderer-service.yaml b/kube-prometheus-stack/charts/grafana/templates/image-renderer-service.yaml
new file mode 100644
index 00000000..fcf707a3
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/image-renderer-service.yaml
@@ -0,0 +1,33 @@
+{{ if .Values.imageRenderer.enabled }}
+{{ if .Values.imageRenderer.service.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "grafana.fullname" . }}-image-renderer
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.imageRenderer.labels" . | nindent 4 }}
+{{- if .Values.imageRenderer.service.labels }}
+{{ toYaml .Values.imageRenderer.service.labels | indent 4 }}
+{{- end }}
+{{- with .Values.imageRenderer.service.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+ type: ClusterIP
+ {{- if .Values.imageRenderer.service.clusterIP }}
+ clusterIP: {{ .Values.imageRenderer.service.clusterIP }}
+ {{end}}
+ ports:
+ - name: {{ .Values.imageRenderer.service.portName }}
+ port: {{ .Values.imageRenderer.service.port }}
+ protocol: TCP
+ targetPort: {{ .Values.imageRenderer.service.targetPort }}
+ {{- if .Values.imageRenderer.appProtocol }}
+ appProtocol: {{ .Values.imageRenderer.appProtocol }}
+ {{- end }}
+ selector:
+ {{- include "grafana.imageRenderer.selectorLabels" . | nindent 4 }}
+{{ end }}
+{{ end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/ingress.yaml b/kube-prometheus-stack/charts/grafana/templates/ingress.yaml
new file mode 100644
index 00000000..7699ceca
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/ingress.yaml
@@ -0,0 +1,78 @@
+{{- if .Values.ingress.enabled -}}
+{{- $ingressApiIsStable := eq (include "grafana.ingress.isStable" .) "true" -}}
+{{- $ingressSupportsIngressClassName := eq (include "grafana.ingress.supportsIngressClassName" .) "true" -}}
+{{- $ingressSupportsPathType := eq (include "grafana.ingress.supportsPathType" .) "true" -}}
+{{- $fullName := include "grafana.fullname" . -}}
+{{- $servicePort := .Values.service.port -}}
+{{- $ingressPath := .Values.ingress.path -}}
+{{- $ingressPathType := .Values.ingress.pathType -}}
+{{- $extraPaths := .Values.ingress.extraPaths -}}
+apiVersion: {{ include "grafana.ingress.apiVersion" . }}
+kind: Ingress
+metadata:
+ name: {{ $fullName }}
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- if .Values.ingress.labels }}
+{{ toYaml .Values.ingress.labels | indent 4 }}
+{{- end }}
+ {{- if .Values.ingress.annotations }}
+ annotations:
+ {{- range $key, $value := .Values.ingress.annotations }}
+ {{ $key }}: {{ tpl $value $ | quote }}
+ {{- end }}
+ {{- end }}
+spec:
+ {{- if and $ingressSupportsIngressClassName .Values.ingress.ingressClassName }}
+ ingressClassName: {{ .Values.ingress.ingressClassName }}
+ {{- end -}}
+{{- if .Values.ingress.tls }}
+ tls:
+{{ tpl (toYaml .Values.ingress.tls) $ | indent 4 }}
+{{- end }}
+ rules:
+ {{- if .Values.ingress.hosts }}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ tpl . $}}
+ http:
+ paths:
+{{- if $extraPaths }}
+{{ toYaml $extraPaths | indent 10 }}
+{{- end }}
+ - path: {{ $ingressPath }}
+ {{- if $ingressSupportsPathType }}
+ pathType: {{ $ingressPathType }}
+ {{- end }}
+ backend:
+ {{- if $ingressApiIsStable }}
+ service:
+ name: {{ $fullName }}
+ port:
+ number: {{ $servicePort }}
+ {{- else }}
+ serviceName: {{ $fullName }}
+ servicePort: {{ $servicePort }}
+ {{- end }}
+ {{- end }}
+ {{- else }}
+ - http:
+ paths:
+ - backend:
+ {{- if $ingressApiIsStable }}
+ service:
+ name: {{ $fullName }}
+ port:
+ number: {{ $servicePort }}
+ {{- else }}
+ serviceName: {{ $fullName }}
+ servicePort: {{ $servicePort }}
+ {{- end }}
+ {{- if $ingressPath }}
+ path: {{ $ingressPath }}
+ {{- end }}
+ {{- if $ingressSupportsPathType }}
+ pathType: {{ $ingressPathType }}
+ {{- end }}
+ {{- end -}}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/networkpolicy.yaml b/kube-prometheus-stack/charts/grafana/templates/networkpolicy.yaml
new file mode 100644
index 00000000..b751d943
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/networkpolicy.yaml
@@ -0,0 +1,52 @@
+{{- if .Values.networkPolicy.enabled }}
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+ {{- with .Values.labels }}
+ {{ toYaml . | nindent 4 }}
+ {{- end }}
+ {{- with .Values.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ policyTypes:
+ {{- if .Values.networkPolicy.ingress }}
+ - Ingress
+ {{- end }}
+ {{- if .Values.networkPolicy.egress.enabled }}
+ - Egress
+ {{- end }}
+ podSelector:
+ matchLabels:
+ {{- include "grafana.selectorLabels" . | nindent 6 }}
+
+ {{- if .Values.networkPolicy.egress.enabled }}
+ egress:
+ - ports:
+ {{ .Values.networkPolicy.egress.ports | toJson }}
+ {{- end }}
+ {{- if .Values.networkPolicy.ingress }}
+ ingress:
+ - ports:
+ - port: {{ .Values.service.targetPort }}
+ {{- if not .Values.networkPolicy.allowExternal }}
+ from:
+ - podSelector:
+ matchLabels:
+ {{ template "grafana.fullname" . }}-client: "true"
+ {{- with .Values.networkPolicy.explicitNamespacesSelector }}
+ - namespaceSelector:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ - podSelector:
+ matchLabels:
+ {{- include "grafana.labels" . | nindent 14 }}
+ role: read
+ {{- end }}
+ {{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/poddisruptionbudget.yaml b/kube-prometheus-stack/charts/grafana/templates/poddisruptionbudget.yaml
new file mode 100644
index 00000000..70901b70
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/poddisruptionbudget.yaml
@@ -0,0 +1,22 @@
+{{- if .Values.podDisruptionBudget }}
+apiVersion: {{ include "grafana.podDisruptionBudget.apiVersion" . }}
+kind: PodDisruptionBudget
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- if .Values.labels }}
+{{ toYaml .Values.labels | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.podDisruptionBudget.minAvailable }}
+ minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
+{{- end }}
+{{- if .Values.podDisruptionBudget.maxUnavailable }}
+ maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
+{{- end }}
+ selector:
+ matchLabels:
+ {{- include "grafana.selectorLabels" . | nindent 6 }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/podsecuritypolicy.yaml b/kube-prometheus-stack/charts/grafana/templates/podsecuritypolicy.yaml
new file mode 100644
index 00000000..d9905c62
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/podsecuritypolicy.yaml
@@ -0,0 +1,51 @@
+{{- if .Values.rbac.pspEnabled }}
+{{- if .Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy" }}
+apiVersion: policy/v1beta1
+kind: PodSecurityPolicy
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+ annotations:
+ seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default,runtime/default'
+ seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
+ {{- if .Values.rbac.pspUseAppArmor }}
+ apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
+ apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
+ {{- end }}
+spec:
+ privileged: false
+ allowPrivilegeEscalation: false
+ requiredDropCapabilities:
+ # Default set from Docker, with DAC_OVERRIDE and CHOWN
+ - ALL
+ volumes:
+ - 'configMap'
+ - 'emptyDir'
+ - 'projected'
+ - 'csi'
+ - 'secret'
+ - 'downwardAPI'
+ - 'persistentVolumeClaim'
+ hostNetwork: false
+ hostIPC: false
+ hostPID: false
+ runAsUser:
+ rule: 'RunAsAny'
+ seLinux:
+ rule: 'RunAsAny'
+ supplementalGroups:
+ rule: 'MustRunAs'
+ ranges:
+ # Forbid adding the root group.
+ - min: 1
+ max: 65535
+ fsGroup:
+ rule: 'MustRunAs'
+ ranges:
+ # Forbid adding the root group.
+ - min: 1
+ max: 65535
+ readOnlyRootFilesystem: false
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/pvc.yaml b/kube-prometheus-stack/charts/grafana/templates/pvc.yaml
new file mode 100644
index 00000000..8d93f5c2
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/pvc.yaml
@@ -0,0 +1,33 @@
+{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) (eq .Values.persistence.type "pvc")}}
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+ {{- with .Values.persistence.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+ {{- end }}
+ {{- with .Values.persistence.finalizers }}
+ finalizers:
+{{ toYaml . | indent 4 }}
+ {{- end }}
+spec:
+ accessModes:
+ {{- range .Values.persistence.accessModes }}
+ - {{ . | quote }}
+ {{- end }}
+ resources:
+ requests:
+ storage: {{ .Values.persistence.size | quote }}
+ {{- if .Values.persistence.storageClassName }}
+ storageClassName: {{ .Values.persistence.storageClassName }}
+ {{- end -}}
+ {{- with .Values.persistence.selectorLabels }}
+ selector:
+ matchLabels:
+{{ toYaml . | indent 6 }}
+ {{- end }}
+{{- end -}}
diff --git a/kube-prometheus-stack/charts/grafana/templates/role.yaml b/kube-prometheus-stack/charts/grafana/templates/role.yaml
new file mode 100644
index 00000000..ff2160f4
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/role.yaml
@@ -0,0 +1,32 @@
+{{- if and .Values.rbac.create (not .Values.rbac.useExistingRole) -}}
+apiVersion: {{ template "grafana.rbac.apiVersion" . }}
+kind: Role
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+{{- if or .Values.rbac.pspEnabled (and .Values.rbac.namespaced (or .Values.sidecar.dashboards.enabled (or .Values.sidecar.datasources.enabled (or .Values.sidecar.plugins.enabled .Values.rbac.extraRoleRules)))) }}
+rules:
+{{- if .Values.rbac.pspEnabled }}
+- apiGroups: ['extensions']
+ resources: ['podsecuritypolicies']
+ verbs: ['use']
+ resourceNames: [{{ template "grafana.fullname" . }}]
+{{- end }}
+{{- if and .Values.rbac.namespaced (or .Values.sidecar.dashboards.enabled (or .Values.sidecar.datasources.enabled .Values.sidecar.plugins.enabled)) }}
+- apiGroups: [""] # "" indicates the core API group
+ resources: ["configmaps", "secrets"]
+ verbs: ["get", "watch", "list"]
+{{- end }}
+{{- with .Values.rbac.extraRoleRules }}
+{{ toYaml . | indent 0 }}
+{{- end}}
+{{- else }}
+rules: []
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/rolebinding.yaml b/kube-prometheus-stack/charts/grafana/templates/rolebinding.yaml
new file mode 100644
index 00000000..e0107255
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/rolebinding.yaml
@@ -0,0 +1,25 @@
+{{- if .Values.rbac.create -}}
+apiVersion: {{ template "grafana.rbac.apiVersion" . }}
+kind: RoleBinding
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+{{- if (not .Values.rbac.useExistingRole) }}
+ name: {{ template "grafana.fullname" . }}
+{{- else }}
+ name: {{ .Values.rbac.useExistingRole }}
+{{- end }}
+subjects:
+- kind: ServiceAccount
+ name: {{ template "grafana.serviceAccountName" . }}
+ namespace: {{ template "grafana.namespace" . }}
+{{- end -}}
diff --git a/kube-prometheus-stack/charts/grafana/templates/secret-env.yaml b/kube-prometheus-stack/charts/grafana/templates/secret-env.yaml
new file mode 100644
index 00000000..5c09313e
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/secret-env.yaml
@@ -0,0 +1,14 @@
+{{- if .Values.envRenderSecret }}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ template "grafana.fullname" . }}-env
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+type: Opaque
+data:
+{{- range $key, $val := .Values.envRenderSecret }}
+ {{ $key }}: {{ $val | b64enc | quote }}
+{{- end -}}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/secret.yaml b/kube-prometheus-stack/charts/grafana/templates/secret.yaml
new file mode 100644
index 00000000..c8aa750a
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/secret.yaml
@@ -0,0 +1,26 @@
+{{- if or (and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION)) (and .Values.ldap.enabled (not .Values.ldap.existingSecret)) }}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+type: Opaque
+data:
+ {{- if and (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) }}
+ admin-user: {{ .Values.adminUser | b64enc | quote }}
+ {{- if .Values.adminPassword }}
+ admin-password: {{ .Values.adminPassword | b64enc | quote }}
+ {{- else }}
+ admin-password: {{ template "grafana.password" . }}
+ {{- end }}
+ {{- end }}
+ {{- if not .Values.ldap.existingSecret }}
+ ldap-toml: {{ tpl .Values.ldap.config $ | b64enc | quote }}
+ {{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/service.yaml b/kube-prometheus-stack/charts/grafana/templates/service.yaml
new file mode 100644
index 00000000..d0a1756c
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/service.yaml
@@ -0,0 +1,55 @@
+{{ if .Values.service.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- if .Values.service.labels }}
+{{ toYaml .Values.service.labels | indent 4 }}
+{{- end }}
+{{- $root := . }}
+{{- with .Values.service.annotations }}
+ annotations:
+{{ tpl (toYaml . | indent 4) $root }}
+{{- end }}
+spec:
+{{- if (or (eq .Values.service.type "ClusterIP") (empty .Values.service.type)) }}
+ type: ClusterIP
+ {{- if .Values.service.clusterIP }}
+ clusterIP: {{ .Values.service.clusterIP }}
+ {{end}}
+{{- else if eq .Values.service.type "LoadBalancer" }}
+ type: {{ .Values.service.type }}
+ {{- if .Values.service.loadBalancerIP }}
+ loadBalancerIP: {{ .Values.service.loadBalancerIP }}
+ {{- end }}
+ {{- if .Values.service.loadBalancerSourceRanges }}
+ loadBalancerSourceRanges:
+{{ toYaml .Values.service.loadBalancerSourceRanges | indent 4 }}
+ {{- end -}}
+{{- else }}
+ type: {{ .Values.service.type }}
+{{- end }}
+{{- if .Values.service.externalIPs }}
+ externalIPs:
+{{ toYaml .Values.service.externalIPs | indent 4 }}
+{{- end }}
+ ports:
+ - name: {{ .Values.service.portName }}
+ port: {{ .Values.service.port }}
+ protocol: TCP
+ targetPort: {{ .Values.service.targetPort }}
+ {{- if .Values.service.appProtocol }}
+ appProtocol: {{ .Values.service.appProtocol }}
+ {{- end }}
+ {{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort))) }}
+ nodePort: {{.Values.service.nodePort}}
+ {{ end }}
+ {{- if .Values.extraExposePorts }}
+ {{- tpl (toYaml .Values.extraExposePorts) . | nindent 4 }}
+ {{- end }}
+ selector:
+ {{- include "grafana.selectorLabels" . | nindent 4 }}
+{{ end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/serviceaccount.yaml b/kube-prometheus-stack/charts/grafana/templates/serviceaccount.yaml
new file mode 100644
index 00000000..4ccee15e
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/serviceaccount.yaml
@@ -0,0 +1,14 @@
+{{- if .Values.serviceAccount.create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- $root := . }}
+{{- with .Values.serviceAccount.annotations }}
+ annotations:
+{{ tpl (toYaml . | indent 4) $root }}
+{{- end }}
+ name: {{ template "grafana.serviceAccountName" . }}
+ namespace: {{ template "grafana.namespace" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/servicemonitor.yaml b/kube-prometheus-stack/charts/grafana/templates/servicemonitor.yaml
new file mode 100644
index 00000000..0876a637
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/servicemonitor.yaml
@@ -0,0 +1,44 @@
+{{- if .Values.serviceMonitor.enabled }}
+---
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ {{- if .Values.serviceMonitor.namespace }}
+ namespace: {{ tpl .Values.serviceMonitor.namespace . }}
+ {{- else }}
+ namespace: {{ template "grafana.namespace" . }}
+ {{- end }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+ {{- if .Values.serviceMonitor.labels }}
+ {{- toYaml .Values.serviceMonitor.labels | nindent 4 }}
+ {{- end }}
+spec:
+ endpoints:
+ - port: {{ .Values.service.portName }}
+ {{- with .Values.serviceMonitor.interval }}
+ interval: {{ . }}
+ {{- end }}
+ {{- with .Values.serviceMonitor.scrapeTimeout }}
+ scrapeTimeout: {{ . }}
+ {{- end }}
+ honorLabels: true
+ path: {{ .Values.serviceMonitor.path }}
+ scheme: {{ .Values.serviceMonitor.scheme }}
+ {{- if .Values.serviceMonitor.tlsConfig }}
+ tlsConfig:
+ {{- toYaml .Values.serviceMonitor.tlsConfig | nindent 6 }}
+ {{- end }}
+ {{- if .Values.serviceMonitor.relabelings }}
+ relabelings:
+ {{- toYaml .Values.serviceMonitor.relabelings | nindent 4 }}
+ {{- end }}
+ jobLabel: "{{ .Release.Name }}"
+ selector:
+ matchLabels:
+ {{- include "grafana.selectorLabels" . | nindent 8 }}
+ namespaceSelector:
+ matchNames:
+ - {{ template "grafana.namespace" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/statefulset.yaml b/kube-prometheus-stack/charts/grafana/templates/statefulset.yaml
new file mode 100644
index 00000000..b308dec4
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/statefulset.yaml
@@ -0,0 +1,54 @@
+{{- if (or (.Values.useStatefulSet) (and .Values.persistence.enabled (not .Values.persistence.existingClaim) (eq .Values.persistence.type "statefulset")))}}
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: {{ template "grafana.fullname" . }}
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+ replicas: {{ .Values.replicas }}
+ selector:
+ matchLabels:
+ {{- include "grafana.selectorLabels" . | nindent 6 }}
+ serviceName: {{ template "grafana.fullname" . }}-headless
+ template:
+ metadata:
+ labels:
+ {{- include "grafana.selectorLabels" . | nindent 8 }}
+{{- with .Values.podLabels }}
+{{ toYaml . | indent 8 }}
+{{- end }}
+ annotations:
+ checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
+ checksum/dashboards-json-config: {{ include (print $.Template.BasePath "/dashboards-json-configmap.yaml") . | sha256sum }}
+ checksum/sc-dashboard-provider-config: {{ include (print $.Template.BasePath "/configmap-dashboard-provider.yaml") . | sha256sum }}
+ {{- if and (or (and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD)) (and .Values.ldap.enabled (not .Values.ldap.existingSecret))) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }}
+ checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
+{{- end }}
+{{- with .Values.podAnnotations }}
+{{ toYaml . | indent 8 }}
+{{- end }}
+ spec:
+ {{- include "grafana.pod" . | nindent 6 }}
+ {{- if .Values.persistence.enabled}}
+ volumeClaimTemplates:
+ - metadata:
+ name: storage
+ spec:
+ accessModes: {{ .Values.persistence.accessModes }}
+ storageClassName: {{ .Values.persistence.storageClassName }}
+ resources:
+ requests:
+ storage: {{ .Values.persistence.size }}
+ {{- with .Values.persistence.selectorLabels }}
+ selector:
+ matchLabels:
+{{ toYaml . | indent 10 }}
+ {{- end }}
+ {{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/tests/test-configmap.yaml b/kube-prometheus-stack/charts/grafana/templates/tests/test-configmap.yaml
new file mode 100644
index 00000000..772ecbbe
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/tests/test-configmap.yaml
@@ -0,0 +1,17 @@
+{{- if .Values.testFramework.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ template "grafana.fullname" . }}-test
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+data:
+ run.sh: |-
+ @test "Test Health" {
+ url="http://{{ template "grafana.fullname" . }}/api/health"
+
+ code=$(wget --server-response --spider --timeout 90 --tries 10 ${url} 2>&1 | awk '/^ HTTP/{print $2}')
+ [ "$code" == "200" ]
+ }
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/tests/test-podsecuritypolicy.yaml b/kube-prometheus-stack/charts/grafana/templates/tests/test-podsecuritypolicy.yaml
new file mode 100644
index 00000000..6ccc7a70
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/tests/test-podsecuritypolicy.yaml
@@ -0,0 +1,31 @@
+{{- if and .Values.testFramework.enabled .Values.rbac.pspEnabled }}
+{{- if .Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy" }}
+apiVersion: policy/v1beta1
+kind: PodSecurityPolicy
+metadata:
+ name: {{ template "grafana.fullname" . }}-test
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+spec:
+ allowPrivilegeEscalation: true
+ privileged: false
+ hostNetwork: false
+ hostIPC: false
+ hostPID: false
+ fsGroup:
+ rule: RunAsAny
+ seLinux:
+ rule: RunAsAny
+ supplementalGroups:
+ rule: RunAsAny
+ runAsUser:
+ rule: RunAsAny
+ volumes:
+ - configMap
+ - downwardAPI
+ - emptyDir
+ - projected
+ - csi
+ - secret
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/tests/test-role.yaml b/kube-prometheus-stack/charts/grafana/templates/tests/test-role.yaml
new file mode 100644
index 00000000..6b10677a
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/tests/test-role.yaml
@@ -0,0 +1,14 @@
+{{- if and .Values.testFramework.enabled .Values.rbac.pspEnabled -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: {{ template "grafana.fullname" . }}-test
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+rules:
+- apiGroups: ['policy']
+ resources: ['podsecuritypolicies']
+ verbs: ['use']
+ resourceNames: [{{ template "grafana.fullname" . }}-test]
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/tests/test-rolebinding.yaml b/kube-prometheus-stack/charts/grafana/templates/tests/test-rolebinding.yaml
new file mode 100644
index 00000000..58fa5e78
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/tests/test-rolebinding.yaml
@@ -0,0 +1,17 @@
+{{- if and .Values.testFramework.enabled .Values.rbac.pspEnabled -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: {{ template "grafana.fullname" . }}-test
+ namespace: {{ template "grafana.namespace" . }}
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: {{ template "grafana.fullname" . }}-test
+subjects:
+- kind: ServiceAccount
+ name: {{ template "grafana.serviceAccountNameTest" . }}
+ namespace: {{ template "grafana.namespace" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/tests/test-serviceaccount.yaml b/kube-prometheus-stack/charts/grafana/templates/tests/test-serviceaccount.yaml
new file mode 100644
index 00000000..5c335073
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/tests/test-serviceaccount.yaml
@@ -0,0 +1,9 @@
+{{- if and .Values.testFramework.enabled .Values.serviceAccount.create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+ name: {{ template "grafana.serviceAccountNameTest" . }}
+ namespace: {{ template "grafana.namespace" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/templates/tests/test.yaml b/kube-prometheus-stack/charts/grafana/templates/tests/test.yaml
new file mode 100644
index 00000000..ef43d80d
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/templates/tests/test.yaml
@@ -0,0 +1,51 @@
+{{- if .Values.testFramework.enabled }}
+apiVersion: v1
+kind: Pod
+metadata:
+ name: {{ template "grafana.fullname" . }}-test
+ labels:
+ {{- include "grafana.labels" . | nindent 4 }}
+ annotations:
+ "helm.sh/hook": test-success
+ "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded"
+ namespace: {{ template "grafana.namespace" . }}
+spec:
+ serviceAccountName: {{ template "grafana.serviceAccountNameTest" . }}
+ {{- if .Values.testFramework.securityContext }}
+ securityContext: {{ toYaml .Values.testFramework.securityContext | nindent 4 }}
+ {{- end }}
+ {{- $root := . }}
+ {{- if .Values.image.pullSecrets }}
+ imagePullSecrets:
+ {{- range .Values.image.pullSecrets }}
+ - name: {{ tpl . $root }}
+ {{- end}}
+ {{- end }}
+ {{- with .Values.nodeSelector }}
+ nodeSelector:
+{{ toYaml . | indent 4 }}
+ {{- end }}
+ {{- $root := . }}
+ {{- with .Values.affinity }}
+ affinity:
+{{ tpl (toYaml .) $root | indent 4 }}
+ {{- end }}
+ {{- with .Values.tolerations }}
+ tolerations:
+{{ toYaml . | indent 4 }}
+ {{- end }}
+ containers:
+ - name: {{ .Release.Name }}-test
+ image: "{{ .Values.testFramework.image}}:{{ .Values.testFramework.tag }}"
+ imagePullPolicy: "{{ .Values.testFramework.imagePullPolicy}}"
+ command: ["/opt/bats/bin/bats", "-t", "/tests/run.sh"]
+ volumeMounts:
+ - mountPath: /tests
+ name: tests
+ readOnly: true
+ volumes:
+ - name: tests
+ configMap:
+ name: {{ template "grafana.fullname" . }}-test
+ restartPolicy: Never
+{{- end }}
diff --git a/kube-prometheus-stack/charts/grafana/values.yaml b/kube-prometheus-stack/charts/grafana/values.yaml
new file mode 100644
index 00000000..adcbbca3
--- /dev/null
+++ b/kube-prometheus-stack/charts/grafana/values.yaml
@@ -0,0 +1,1128 @@
+rbac:
+ create: true
+ ## Use an existing ClusterRole/Role (depending on rbac.namespaced false/true)
+ # useExistingRole: name-of-some-(cluster)role
+ pspEnabled: true
+ pspUseAppArmor: true
+ namespaced: false
+ extraRoleRules: []
+ # - apiGroups: []
+ # resources: []
+ # verbs: []
+ extraClusterRoleRules: []
+ # - apiGroups: []
+ # resources: []
+ # verbs: []
+serviceAccount:
+ create: true
+ name:
+ nameTest:
+## Service account annotations. Can be templated.
+# annotations:
+# eks.amazonaws.com/role-arn: arn:aws:iam::123456789000:role/iam-role-name-here
+ autoMount: true
+
+replicas: 1
+
+## Create a headless service for the deployment
+headlessService: false
+
+## Create HorizontalPodAutoscaler object for deployment type
+#
+autoscaling:
+ enabled: false
+# minReplicas: 1
+# maxReplicas: 10
+# metrics:
+# - type: Resource
+# resource:
+# name: cpu
+# targetAverageUtilization: 60
+# - type: Resource
+# resource:
+# name: memory
+# targetAverageUtilization: 60
+
+## See `kubectl explain poddisruptionbudget.spec` for more
+## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/
+podDisruptionBudget: {}
+# minAvailable: 1
+# maxUnavailable: 1
+
+## See `kubectl explain deployment.spec.strategy` for more
+## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy
+deploymentStrategy:
+ type: RollingUpdate
+
+readinessProbe:
+ httpGet:
+ path: /api/health
+ port: 3000
+
+livenessProbe:
+ httpGet:
+ path: /api/health
+ port: 3000
+ initialDelaySeconds: 60
+ timeoutSeconds: 30
+ failureThreshold: 10
+
+## Use an alternate scheduler, e.g. "stork".
+## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
+##
+# schedulerName: "default-scheduler"
+
+image:
+ repository: grafana/grafana
+ # Overrides the Grafana image tag whose default is the chart appVersion
+ tag: ""
+ sha: ""
+ pullPolicy: IfNotPresent
+
+ ## Optionally specify an array of imagePullSecrets.
+ ## Secrets must be manually created in the namespace.
+ ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
+ ## Can be templated.
+ ##
+ # pullSecrets:
+ # - myRegistrKeySecretName
+
+testFramework:
+ enabled: true
+ image: "bats/bats"
+ tag: "v1.4.1"
+ imagePullPolicy: IfNotPresent
+ securityContext: {}
+
+securityContext:
+ runAsUser: 472
+ runAsGroup: 472
+ fsGroup: 472
+
+containerSecurityContext:
+ {}
+
+# Enable creating the grafana configmap
+createConfigmap: true
+
+# Extra configmaps to mount in grafana pods
+# Values are templated.
+extraConfigmapMounts: []
+ # - name: certs-configmap
+ # mountPath: /etc/grafana/ssl/
+ # subPath: certificates.crt # (optional)
+ # configMap: certs-configmap
+ # readOnly: true
+
+
+extraEmptyDirMounts: []
+ # - name: provisioning-notifiers
+ # mountPath: /etc/grafana/provisioning/notifiers
+
+
+# Apply extra labels to common labels.
+extraLabels: {}
+
+## Assign a PriorityClassName to pods if set
+# priorityClassName:
+
+downloadDashboardsImage:
+ repository: curlimages/curl
+ tag: 7.85.0
+ sha: ""
+ pullPolicy: IfNotPresent
+
+downloadDashboards:
+ env: {}
+ envFromSecret: ""
+ resources: {}
+ securityContext: {}
+
+## Pod Annotations
+# podAnnotations: {}
+
+## Pod Labels
+# podLabels: {}
+
+podPortName: grafana
+
+## Deployment annotations
+# annotations: {}
+
+## Expose the grafana service to be accessed from outside the cluster (LoadBalancer service).
+## or access it from within the cluster (ClusterIP service). Set the service type and the port to serve it.
+## ref: http://kubernetes.io/docs/user-guide/services/
+##
+service:
+ enabled: true
+ type: ClusterIP
+ port: 80
+ targetPort: 3000
+ # targetPort: 4181 To be used with a proxy extraContainer
+ ## Service annotations. Can be templated.
+ annotations: {}
+ labels: {}
+ portName: service
+ # Adds the appProtocol field to the service. This allows to work with istio protocol selection. Ex: "http" or "tcp"
+ appProtocol: ""
+
+serviceMonitor:
+ ## If true, a ServiceMonitor CRD is created for a prometheus operator
+ ## https://github.com/coreos/prometheus-operator
+ ##
+ enabled: false
+ path: /metrics
+ # namespace: monitoring (defaults to use the namespace this chart is deployed to)
+ labels: {}
+ interval: 1m
+ scheme: http
+ tlsConfig: {}
+ scrapeTimeout: 30s
+ relabelings: []
+
+extraExposePorts: []
+ # - name: keycloak
+ # port: 8080
+ # targetPort: 8080
+ # type: ClusterIP
+
+# overrides pod.spec.hostAliases in the grafana deployment's pods
+hostAliases: []
+ # - ip: "1.2.3.4"
+ # hostnames:
+ # - "my.host.com"
+
+ingress:
+ enabled: false
+ # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
+ # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
+ # ingressClassName: nginx
+ # Values can be templated
+ annotations: {}
+ # kubernetes.io/ingress.class: nginx
+ # kubernetes.io/tls-acme: "true"
+ labels: {}
+ path: /
+
+ # pathType is only for k8s >= 1.1=
+ pathType: Prefix
+
+ hosts:
+ - chart-example.local
+ ## Extra paths to prepend to every host configuration. This is useful when working with annotation based services.
+ extraPaths: []
+ # - path: /*
+ # backend:
+ # serviceName: ssl-redirect
+ # servicePort: use-annotation
+ ## Or for k8s > 1.19
+ # - path: /*
+ # pathType: Prefix
+ # backend:
+ # service:
+ # name: ssl-redirect
+ # port:
+ # name: use-annotation
+
+
+ tls: []
+ # - secretName: chart-example-tls
+ # hosts:
+ # - chart-example.local
+
+resources: {}
+# limits:
+# cpu: 100m
+# memory: 128Mi
+# requests:
+# cpu: 100m
+# memory: 128Mi
+
+## Node labels for pod assignment
+## ref: https://kubernetes.io/docs/user-guide/node-selection/
+#
+nodeSelector: {}
+
+## Tolerations for pod assignment
+## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+##
+tolerations: []
+
+## Affinity for pod assignment (evaluated as template)
+## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
+##
+affinity: {}
+
+## Topology Spread Constraints
+## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
+##
+topologySpreadConstraints: []
+
+## Additional init containers (evaluated as template)
+## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
+##
+extraInitContainers: []
+
+## Enable an Specify container in extraContainers. This is meant to allow adding an authentication proxy to a grafana pod
+extraContainers: ""
+# extraContainers: |
+# - name: proxy
+# image: quay.io/gambol99/keycloak-proxy:latest
+# args:
+# - -provider=github
+# - -client-id=
+# - -client-secret=
+# - -github-org=
+# - -email-domain=*
+# - -cookie-secret=
+# - -http-address=http://0.0.0.0:4181
+# - -upstream-url=http://127.0.0.1:3000
+# ports:
+# - name: proxy-web
+# containerPort: 4181
+
+## Volumes that can be used in init containers that will not be mounted to deployment pods
+extraContainerVolumes: []
+# - name: volume-from-secret
+# secret:
+# secretName: secret-to-mount
+# - name: empty-dir-volume
+# emptyDir: {}
+
+## Enable persistence using Persistent Volume Claims
+## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
+##
+persistence:
+ type: pvc
+ enabled: false
+ # storageClassName: default
+ accessModes:
+ - ReadWriteOnce
+ size: 10Gi
+ # annotations: {}
+ finalizers:
+ - kubernetes.io/pvc-protection
+ # selectorLabels: {}
+ ## Sub-directory of the PV to mount. Can be templated.
+ # subPath: ""
+ ## Name of an existing PVC. Can be templated.
+ # existingClaim:
+
+ ## If persistence is not enabled, this allows to mount the
+ ## local storage in-memory to improve performance
+ ##
+ inMemory:
+ enabled: false
+ ## The maximum usage on memory medium EmptyDir would be
+ ## the minimum value between the SizeLimit specified
+ ## here and the sum of memory limits of all containers in a pod
+ ##
+ # sizeLimit: 300Mi
+
+initChownData:
+ ## If false, data ownership will not be reset at startup
+ ## This allows the prometheus-server to be run with an arbitrary user
+ ##
+ enabled: true
+
+ ## initChownData container image
+ ##
+ image:
+ repository: busybox
+ tag: "1.31.1"
+ sha: ""
+ pullPolicy: IfNotPresent
+
+ ## initChownData resource requests and limits
+ ## Ref: http://kubernetes.io/docs/user-guide/compute-resources/
+ ##
+ resources: {}
+ # limits:
+ # cpu: 100m
+ # memory: 128Mi
+ # requests:
+ # cpu: 100m
+ # memory: 128Mi
+
+
+# Administrator credentials when not using an existing secret (see below)
+adminUser: admin
+# adminPassword: strongpassword
+
+# Use an existing secret for the admin user.
+admin:
+ ## Name of the secret. Can be templated.
+ existingSecret: ""
+ userKey: admin-user
+ passwordKey: admin-password
+
+## Define command to be executed at startup by grafana container
+## Needed if using `vault-env` to manage secrets (ref: https://banzaicloud.com/blog/inject-secrets-into-pods-vault/)
+## Default is "run.sh" as defined in grafana's Dockerfile
+# command:
+# - "sh"
+# - "/run.sh"
+
+## Use an alternate scheduler, e.g. "stork".
+## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
+##
+# schedulerName:
+
+## Extra environment variables that will be pass onto deployment pods
+##
+## to provide grafana with access to CloudWatch on AWS EKS:
+## 1. create an iam role of type "Web identity" with provider oidc.eks.* (note the provider for later)
+## 2. edit the "Trust relationships" of the role, add a line inside the StringEquals clause using the
+## same oidc eks provider as noted before (same as the existing line)
+## also, replace NAMESPACE and prometheus-operator-grafana with the service account namespace and name
+##
+## "oidc.eks.us-east-1.amazonaws.com/id/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:sub": "system:serviceaccount:NAMESPACE:prometheus-operator-grafana",
+##
+## 3. attach a policy to the role, you can use a built in policy called CloudWatchReadOnlyAccess
+## 4. use the following env: (replace 123456789000 and iam-role-name-here with your aws account number and role name)
+##
+## env:
+## AWS_ROLE_ARN: arn:aws:iam::123456789000:role/iam-role-name-here
+## AWS_WEB_IDENTITY_TOKEN_FILE: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
+## AWS_REGION: us-east-1
+##
+## 5. uncomment the EKS section in extraSecretMounts: below
+## 6. uncomment the annotation section in the serviceAccount: above
+## make sure to replace arn:aws:iam::123456789000:role/iam-role-name-here with your role arn
+
+env: {}
+
+## "valueFrom" environment variable references that will be added to deployment pods. Name is templated.
+## ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#envvarsource-v1-core
+## Renders in container spec as:
+## env:
+## ...
+## - name:
+## valueFrom:
+##
+envValueFrom: {}
+ # ENV_NAME:
+ # configMapKeyRef:
+ # name: configmap-name
+ # key: value_key
+
+## The name of a secret in the same kubernetes namespace which contain values to be added to the environment
+## This can be useful for auth tokens, etc. Value is templated.
+envFromSecret: ""
+
+## Sensible environment variables that will be rendered as new secret object
+## This can be useful for auth tokens, etc
+envRenderSecret: {}
+
+## The names of secrets in the same kubernetes namespace which contain values to be added to the environment
+## Each entry should contain a name key, and can optionally specify whether the secret must be defined with an optional key.
+## Name is templated.
+envFromSecrets: []
+## - name: secret-name
+## optional: true
+
+## The names of conifgmaps in the same kubernetes namespace which contain values to be added to the environment
+## Each entry should contain a name key, and can optionally specify whether the configmap must be defined with an optional key.
+## Name is templated.
+## ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#configmapenvsource-v1-core
+envFromConfigMaps: []
+## - name: configmap-name
+## optional: true
+
+# Inject Kubernetes services as environment variables.
+# See https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/#environment-variables
+enableServiceLinks: true
+
+## Additional grafana server secret mounts
+# Defines additional mounts with secrets. Secrets must be manually created in the namespace.
+extraSecretMounts: []
+ # - name: secret-files
+ # mountPath: /etc/secrets
+ # secretName: grafana-secret-files
+ # readOnly: true
+ # subPath: ""
+ #
+ # for AWS EKS (cloudwatch) use the following (see also instruction in env: above)
+ # - name: aws-iam-token
+ # mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
+ # readOnly: true
+ # projected:
+ # defaultMode: 420
+ # sources:
+ # - serviceAccountToken:
+ # audience: sts.amazonaws.com
+ # expirationSeconds: 86400
+ # path: token
+ #
+ # for CSI e.g. Azure Key Vault use the following
+ # - name: secrets-store-inline
+ # mountPath: /run/secrets
+ # readOnly: true
+ # csi:
+ # driver: secrets-store.csi.k8s.io
+ # readOnly: true
+ # volumeAttributes:
+ # secretProviderClass: "akv-grafana-spc"
+ # nodePublishSecretRef: # Only required when using service principal mode
+ # name: grafana-akv-creds # Only required when using service principal mode
+
+## Additional grafana server volume mounts
+# Defines additional volume mounts.
+extraVolumeMounts: []
+ # - name: extra-volume-0
+ # mountPath: /mnt/volume0
+ # readOnly: true
+ # existingClaim: volume-claim
+ # - name: extra-volume-1
+ # mountPath: /mnt/volume1
+ # readOnly: true
+ # hostPath: /usr/shared/
+ # - name: grafana-secrets
+ # csi: true
+ # data:
+ # driver: secrets-store.csi.k8s.io
+ # readOnly: true
+ # volumeAttributes:
+ # secretProviderClass: "grafana-env-spc"
+
+## Container Lifecycle Hooks. Execute a specific bash command or make an HTTP request
+lifecycleHooks: {}
+ # postStart:
+ # exec:
+ # command: []
+
+## Pass the plugins you want installed as a list.
+##
+plugins: []
+ # - digrich-bubblechart-panel
+ # - grafana-clock-panel
+
+## Configure grafana datasources
+## ref: http://docs.grafana.org/administration/provisioning/#datasources
+##
+datasources: {}
+# datasources.yaml:
+# apiVersion: 1
+# datasources:
+# - name: Prometheus
+# type: prometheus
+# url: http://prometheus-prometheus-server
+# access: proxy
+# isDefault: true
+# - name: CloudWatch
+# type: cloudwatch
+# access: proxy
+# uid: cloudwatch
+# editable: false
+# jsonData:
+# authType: default
+# defaultRegion: us-east-1
+
+## Configure grafana alerting (can be templated)
+## ref: http://docs.grafana.org/administration/provisioning/#alerting
+##
+alerting: {}
+ # rules.yaml:
+ # apiVersion: 1
+ # groups:
+ # - orgId: 1
+ # name: '{{ .Chart.Name }}_my_rule_group'
+ # folder: my_first_folder
+ # interval: 60s
+ # rules:
+ # - uid: my_id_1
+ # title: my_first_rule
+ # condition: A
+ # data:
+ # - refId: A
+ # datasourceUid: '-100'
+ # model:
+ # conditions:
+ # - evaluator:
+ # params:
+ # - 3
+ # type: gt
+ # operator:
+ # type: and
+ # query:
+ # params:
+ # - A
+ # reducer:
+ # type: last
+ # type: query
+ # datasource:
+ # type: __expr__
+ # uid: '-100'
+ # expression: 1==0
+ # intervalMs: 1000
+ # maxDataPoints: 43200
+ # refId: A
+ # type: math
+ # dashboardUid: my_dashboard
+ # panelId: 123
+ # noDataState: Alerting
+ # for: 60s
+ # annotations:
+ # some_key: some_value
+ # labels:
+ # team: sre_team_1
+ # contactpoints.yaml:
+ # apiVersion: 1
+ # contactPoints:
+ # - orgId: 1
+ # name: cp_1
+ # receivers:
+ # - uid: first_uid
+ # type: pagerduty
+ # settings:
+ # integrationKey: XXX
+ # severity: critical
+ # class: ping failure
+ # component: Grafana
+ # group: app-stack
+ # summary: |
+ # {{ `{{ template "default.message" . }}` }}
+
+## Configure notifiers
+## ref: http://docs.grafana.org/administration/provisioning/#alert-notification-channels
+##
+notifiers: {}
+# notifiers.yaml:
+# notifiers:
+# - name: email-notifier
+# type: email
+# uid: email1
+# # either:
+# org_id: 1
+# # or
+# org_name: Main Org.
+# is_default: true
+# settings:
+# addresses: an_email_address@example.com
+# delete_notifiers:
+
+## Configure grafana dashboard providers
+## ref: http://docs.grafana.org/administration/provisioning/#dashboards
+##
+## `path` must be /var/lib/grafana/dashboards/
+##
+dashboardProviders: {}
+# dashboardproviders.yaml:
+# apiVersion: 1
+# providers:
+# - name: 'default'
+# orgId: 1
+# folder: ''
+# type: file
+# disableDeletion: false
+# editable: true
+# options:
+# path: /var/lib/grafana/dashboards/default
+
+## Configure grafana dashboard to import
+## NOTE: To use dashboards you must also enable/configure dashboardProviders
+## ref: https://grafana.com/dashboards
+##
+## dashboards per provider, use provider name as key.
+##
+dashboards: {}
+ # default:
+ # some-dashboard:
+ # json: |
+ # $RAW_JSON
+ # custom-dashboard:
+ # file: dashboards/custom-dashboard.json
+ # prometheus-stats:
+ # gnetId: 2
+ # revision: 2
+ # datasource: Prometheus
+ # local-dashboard:
+ # url: https://example.com/repository/test.json
+ # token: ''
+ # local-dashboard-base64:
+ # url: https://example.com/repository/test-b64.json
+ # token: ''
+ # b64content: true
+ # local-dashboard-gitlab:
+ # url: https://example.com/repository/test-gitlab.json
+ # gitlabToken: ''
+ # local-dashboard-bitbucket:
+ # url: https://example.com/repository/test-bitbucket.json
+ # bearerToken: ''
+
+## Reference to external ConfigMap per provider. Use provider name as key and ConfigMap name as value.
+## A provider dashboards must be defined either by external ConfigMaps or in values.yaml, not in both.
+## ConfigMap data example:
+##
+## data:
+## example-dashboard.json: |
+## RAW_JSON
+##
+dashboardsConfigMaps: {}
+# default: ""
+
+## Grafana's primary configuration
+## NOTE: values in map will be converted to ini format
+## ref: http://docs.grafana.org/installation/configuration/
+##
+grafana.ini:
+ paths:
+ data: /var/lib/grafana/
+ logs: /var/log/grafana
+ plugins: /var/lib/grafana/plugins
+ provisioning: /etc/grafana/provisioning
+ analytics:
+ check_for_updates: true
+ log:
+ mode: console
+ grafana_net:
+ url: https://grafana.net
+ server:
+ domain: "{{ if (and .Values.ingress.enabled .Values.ingress.hosts) }}{{ .Values.ingress.hosts | first }}{{ else }}''{{ end }}"
+## grafana Authentication can be enabled with the following values on grafana.ini
+ # server:
+ # The full public facing url you use in browser, used for redirects and emails
+ # root_url:
+ # https://grafana.com/docs/grafana/latest/auth/github/#enable-github-in-grafana
+ # auth.github:
+ # enabled: false
+ # allow_sign_up: false
+ # scopes: user:email,read:org
+ # auth_url: https://github.com/login/oauth/authorize
+ # token_url: https://github.com/login/oauth/access_token
+ # api_url: https://api.github.com/user
+ # team_ids:
+ # allowed_organizations:
+ # client_id:
+ # client_secret:
+## LDAP Authentication can be enabled with the following values on grafana.ini
+## NOTE: Grafana will fail to start if the value for ldap.toml is invalid
+ # auth.ldap:
+ # enabled: true
+ # allow_sign_up: true
+ # config_file: /etc/grafana/ldap.toml
+
+## Grafana's LDAP configuration
+## Templated by the template in _helpers.tpl
+## NOTE: To enable the grafana.ini must be configured with auth.ldap.enabled
+## ref: http://docs.grafana.org/installation/configuration/#auth-ldap
+## ref: http://docs.grafana.org/installation/ldap/#configuration
+ldap:
+ enabled: false
+ # `existingSecret` is a reference to an existing secret containing the ldap configuration
+ # for Grafana in a key `ldap-toml`.
+ existingSecret: ""
+ # `config` is the content of `ldap.toml` that will be stored in the created secret
+ config: ""
+ # config: |-
+ # verbose_logging = true
+
+ # [[servers]]
+ # host = "my-ldap-server"
+ # port = 636
+ # use_ssl = true
+ # start_tls = false
+ # ssl_skip_verify = false
+ # bind_dn = "uid=%s,ou=users,dc=myorg,dc=com"
+
+## Grafana's SMTP configuration
+## NOTE: To enable, grafana.ini must be configured with smtp.enabled
+## ref: http://docs.grafana.org/installation/configuration/#smtp
+smtp:
+ # `existingSecret` is a reference to an existing secret containing the smtp configuration
+ # for Grafana.
+ existingSecret: ""
+ userKey: "user"
+ passwordKey: "password"
+
+## Sidecars that collect the configmaps with specified label and stores the included files them into the respective folders
+## Requires at least Grafana 5 to work and can't be used together with parameters dashboardProviders, datasources and dashboards
+sidecar:
+ image:
+ repository: quay.io/kiwigrid/k8s-sidecar
+ tag: 1.19.2
+ sha: ""
+ imagePullPolicy: IfNotPresent
+ resources: {}
+# limits:
+# cpu: 100m
+# memory: 100Mi
+# requests:
+# cpu: 50m
+# memory: 50Mi
+ securityContext: {}
+ # skipTlsVerify Set to true to skip tls verification for kube api calls
+ # skipTlsVerify: true
+ enableUniqueFilenames: false
+ readinessProbe: {}
+ livenessProbe: {}
+ # Log level default for all sidecars. Can be one of: DEBUG, INFO, WARN, ERROR, CRITICAL. Defaults to INFO
+ # logLevel: INFO
+ alerts:
+ enabled: false
+ # Additional environment variables for the alerts sidecar
+ env: {}
+ # Do not reprocess already processed unchanged resources on k8s API reconnect.
+ # ignoreAlreadyProcessed: true
+ # label that the configmaps with alert are marked with
+ label: grafana_alert
+ # value of label that the configmaps with alert are set to
+ labelValue: ""
+ # Log level. Can be one of: DEBUG, INFO, WARN, ERROR, CRITICAL.
+ # logLevel: INFO
+ # If specified, the sidecar will search for alert config-maps inside this namespace.
+ # Otherwise the namespace in which the sidecar is running will be used.
+ # It's also possible to specify ALL to search in all namespaces
+ searchNamespace: null
+ # Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds.
+ watchMethod: WATCH
+ # search in configmap, secret or both
+ resource: both
+ # watchServerTimeout: request to the server, asking it to cleanly close the connection after that.
+ # defaults to 60sec; much higher values like 3600 seconds (1h) are feasible for non-Azure K8S
+ # watchServerTimeout: 3600
+ #
+ # watchClientTimeout: is a client-side timeout, configuring your local socket.
+ # If you have a network outage dropping all packets with no RST/FIN,
+ # this is how long your client waits before realizing & dropping the connection.
+ # defaults to 66sec (sic!)
+ # watchClientTimeout: 60
+ #
+ # Endpoint to send request to reload alerts
+ reloadURL: "http://localhost:3000/api/admin/provisioning/alerting/reload"
+ # Absolute path to shell script to execute after a alert got reloaded
+ script: null
+ skipReload: false
+ # Deploy the alert sidecar as an initContainer in addition to a container.
+ # Sets the size limit of the alert sidecar emptyDir volume
+ sizeLimit: {}
+ dashboards:
+ enabled: false
+ # Additional environment variables for the dashboards sidecar
+ env: {}
+ # Do not reprocess already processed unchanged resources on k8s API reconnect.
+ # ignoreAlreadyProcessed: true
+ SCProvider: true
+ # label that the configmaps with dashboards are marked with
+ label: grafana_dashboard
+ # value of label that the configmaps with dashboards are set to
+ labelValue: ""
+ # Log level. Can be one of: DEBUG, INFO, WARN, ERROR, CRITICAL.
+ # logLevel: INFO
+ # folder in the pod that should hold the collected dashboards (unless `defaultFolderName` is set)
+ folder: /tmp/dashboards
+ # The default folder name, it will create a subfolder under the `folder` and put dashboards in there instead
+ defaultFolderName: null
+ # Namespaces list. If specified, the sidecar will search for config-maps/secrets inside these namespaces.
+ # Otherwise the namespace in which the sidecar is running will be used.
+ # It's also possible to specify ALL to search in all namespaces.
+ searchNamespace: null
+ # Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds.
+ watchMethod: WATCH
+ # search in configmap, secret or both
+ resource: both
+ # If specified, the sidecar will look for annotation with this name to create folder and put graph here.
+ # You can use this parameter together with `provider.foldersFromFilesStructure`to annotate configmaps and create folder structure.
+ folderAnnotation: null
+ # Absolute path to shell script to execute after a configmap got reloaded
+ script: null
+ # watchServerTimeout: request to the server, asking it to cleanly close the connection after that.
+ # defaults to 60sec; much higher values like 3600 seconds (1h) are feasible for non-Azure K8S
+ # watchServerTimeout: 3600
+ #
+ # watchClientTimeout: is a client-side timeout, configuring your local socket.
+ # If you have a network outage dropping all packets with no RST/FIN,
+ # this is how long your client waits before realizing & dropping the connection.
+ # defaults to 66sec (sic!)
+ # watchClientTimeout: 60
+ #
+ # provider configuration that lets grafana manage the dashboards
+ provider:
+ # name of the provider, should be unique
+ name: sidecarProvider
+ # orgid as configured in grafana
+ orgid: 1
+ # folder in which the dashboards should be imported in grafana
+ folder: ''
+ # type of the provider
+ type: file
+ # disableDelete to activate a import-only behaviour
+ disableDelete: false
+ # allow updating provisioned dashboards from the UI
+ allowUiUpdates: false
+ # allow Grafana to replicate dashboard structure from filesystem
+ foldersFromFilesStructure: false
+ # Additional dashboard sidecar volume mounts
+ extraMounts: []
+ # Sets the size limit of the dashboard sidecar emptyDir volume
+ sizeLimit: {}
+ datasources:
+ enabled: false
+ # Additional environment variables for the datasourcessidecar
+ env: {}
+ # Do not reprocess already processed unchanged resources on k8s API reconnect.
+ # ignoreAlreadyProcessed: true
+ # label that the configmaps with datasources are marked with
+ label: grafana_datasource
+ # value of label that the configmaps with datasources are set to
+ labelValue: ""
+ # Log level. Can be one of: DEBUG, INFO, WARN, ERROR, CRITICAL.
+ # logLevel: INFO
+ # If specified, the sidecar will search for datasource config-maps inside this namespace.
+ # Otherwise the namespace in which the sidecar is running will be used.
+ # It's also possible to specify ALL to search in all namespaces
+ searchNamespace: null
+ # Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds.
+ watchMethod: WATCH
+ # search in configmap, secret or both
+ resource: both
+ # watchServerTimeout: request to the server, asking it to cleanly close the connection after that.
+ # defaults to 60sec; much higher values like 3600 seconds (1h) are feasible for non-Azure K8S
+ # watchServerTimeout: 3600
+ #
+ # watchClientTimeout: is a client-side timeout, configuring your local socket.
+ # If you have a network outage dropping all packets with no RST/FIN,
+ # this is how long your client waits before realizing & dropping the connection.
+ # defaults to 66sec (sic!)
+ # watchClientTimeout: 60
+ #
+ # Endpoint to send request to reload datasources
+ reloadURL: "http://localhost:3000/api/admin/provisioning/datasources/reload"
+ # Absolute path to shell script to execute after a datasource got reloaded
+ script: null
+ skipReload: false
+ # Deploy the datasource sidecar as an initContainer in addition to a container.
+ # This is needed if skipReload is true, to load any datasources defined at startup time.
+ initDatasources: false
+ # Sets the size limit of the datasource sidecar emptyDir volume
+ sizeLimit: {}
+ plugins:
+ enabled: false
+ # Additional environment variables for the plugins sidecar
+ env: {}
+ # Do not reprocess already processed unchanged resources on k8s API reconnect.
+ # ignoreAlreadyProcessed: true
+ # label that the configmaps with plugins are marked with
+ label: grafana_plugin
+ # value of label that the configmaps with plugins are set to
+ labelValue: ""
+ # Log level. Can be one of: DEBUG, INFO, WARN, ERROR, CRITICAL.
+ # logLevel: INFO
+ # If specified, the sidecar will search for plugin config-maps inside this namespace.
+ # Otherwise the namespace in which the sidecar is running will be used.
+ # It's also possible to specify ALL to search in all namespaces
+ searchNamespace: null
+ # Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds.
+ watchMethod: WATCH
+ # search in configmap, secret or both
+ resource: both
+ # watchServerTimeout: request to the server, asking it to cleanly close the connection after that.
+ # defaults to 60sec; much higher values like 3600 seconds (1h) are feasible for non-Azure K8S
+ # watchServerTimeout: 3600
+ #
+ # watchClientTimeout: is a client-side timeout, configuring your local socket.
+ # If you have a network outage dropping all packets with no RST/FIN,
+ # this is how long your client waits before realizing & dropping the connection.
+ # defaults to 66sec (sic!)
+ # watchClientTimeout: 60
+ #
+ # Endpoint to send request to reload plugins
+ reloadURL: "http://localhost:3000/api/admin/provisioning/plugins/reload"
+ # Absolute path to shell script to execute after a plugin got reloaded
+ script: null
+ skipReload: false
+ # Deploy the datasource sidecar as an initContainer in addition to a container.
+ # This is needed if skipReload is true, to load any plugins defined at startup time.
+ initPlugins: false
+ # Sets the size limit of the plugin sidecar emptyDir volume
+ sizeLimit: {}
+ notifiers:
+ enabled: false
+ # Additional environment variables for the notifierssidecar
+ env: {}
+ # Do not reprocess already processed unchanged resources on k8s API reconnect.
+ # ignoreAlreadyProcessed: true
+ # label that the configmaps with notifiers are marked with
+ label: grafana_notifier
+ # value of label that the configmaps with notifiers are set to
+ labelValue: ""
+ # Log level. Can be one of: DEBUG, INFO, WARN, ERROR, CRITICAL.
+ # logLevel: INFO
+ # If specified, the sidecar will search for notifier config-maps inside this namespace.
+ # Otherwise the namespace in which the sidecar is running will be used.
+ # It's also possible to specify ALL to search in all namespaces
+ searchNamespace: null
+ # Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds.
+ watchMethod: WATCH
+ # search in configmap, secret or both
+ resource: both
+ # watchServerTimeout: request to the server, asking it to cleanly close the connection after that.
+ # defaults to 60sec; much higher values like 3600 seconds (1h) are feasible for non-Azure K8S
+ # watchServerTimeout: 3600
+ #
+ # watchClientTimeout: is a client-side timeout, configuring your local socket.
+ # If you have a network outage dropping all packets with no RST/FIN,
+ # this is how long your client waits before realizing & dropping the connection.
+ # defaults to 66sec (sic!)
+ # watchClientTimeout: 60
+ #
+ # Endpoint to send request to reload notifiers
+ reloadURL: "http://localhost:3000/api/admin/provisioning/notifications/reload"
+ # Absolute path to shell script to execute after a notifier got reloaded
+ script: null
+ skipReload: false
+ # Deploy the notifier sidecar as an initContainer in addition to a container.
+ # This is needed if skipReload is true, to load any notifiers defined at startup time.
+ initNotifiers: false
+ # Sets the size limit of the notifier sidecar emptyDir volume
+ sizeLimit: {}
+
+## Override the deployment namespace
+##
+namespaceOverride: ""
+
+## Number of old ReplicaSets to retain
+##
+revisionHistoryLimit: 10
+
+## Add a seperate remote image renderer deployment/service
+imageRenderer:
+ # Enable the image-renderer deployment & service
+ enabled: false
+ replicas: 1
+ image:
+ # image-renderer Image repository
+ repository: grafana/grafana-image-renderer
+ # image-renderer Image tag
+ tag: latest
+ # image-renderer Image sha (optional)
+ sha: ""
+ # image-renderer ImagePullPolicy
+ pullPolicy: Always
+ # extra environment variables
+ env:
+ HTTP_HOST: "0.0.0.0"
+ # RENDERING_ARGS: --no-sandbox,--disable-gpu,--window-size=1280x758
+ # RENDERING_MODE: clustered
+ # IGNORE_HTTPS_ERRORS: true
+ # image-renderer deployment serviceAccount
+ serviceAccountName: ""
+ # image-renderer deployment securityContext
+ securityContext: {}
+ # image-renderer deployment Host Aliases
+ hostAliases: []
+ # image-renderer deployment priority class
+ priorityClassName: ''
+ service:
+ # Enable the image-renderer service
+ enabled: true
+ # image-renderer service port name
+ portName: 'http'
+ # image-renderer service port used by both service and deployment
+ port: 8081
+ targetPort: 8081
+ # Adds the appProtocol field to the image-renderer service. This allows to work with istio protocol selection. Ex: "http" or "tcp"
+ appProtocol: ""
+ # If https is enabled in Grafana, this needs to be set as 'https' to correctly configure the callback used in Grafana
+ grafanaProtocol: http
+ # In case a sub_path is used this needs to be added to the image renderer callback
+ grafanaSubPath: ""
+ # name of the image-renderer port on the pod
+ podPortName: http
+ # number of image-renderer replica sets to keep
+ revisionHistoryLimit: 10
+ networkPolicy:
+ # Enable a NetworkPolicy to limit inbound traffic to only the created grafana pods
+ limitIngress: true
+ # Enable a NetworkPolicy to limit outbound traffic to only the created grafana pods
+ limitEgress: false
+ resources: {}
+# limits:
+# cpu: 100m
+# memory: 100Mi
+# requests:
+# cpu: 50m
+# memory: 50Mi
+ ## Node labels for pod assignment
+ ## ref: https://kubernetes.io/docs/user-guide/node-selection/
+ #
+ nodeSelector: {}
+
+ ## Tolerations for pod assignment
+ ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+ ##
+ tolerations: []
+
+ ## Affinity for pod assignment (evaluated as template)
+ ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
+ ##
+ affinity: {}
+
+networkPolicy:
+ ## @param networkPolicy.enabled Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now.
+ ##
+ enabled: false
+ ## @param networkPolicy.allowExternal Don't require client label for connections
+ ## The Policy model to apply. When set to false, only pods with the correct
+ ## client label will have network access to grafana port defined.
+ ## When true, grafana will accept connections from any source
+ ## (with the correct destination port).
+ ##
+ ingress: true
+ ## @param networkPolicy.ingress When true enables the creation
+ ## an ingress network policy
+ ##
+ allowExternal: true
+ ## @param networkPolicy.explicitNamespacesSelector A Kubernetes LabelSelector to explicitly select namespaces from which traffic could be allowed
+ ## If explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace
+ ## and that match other criteria, the ones that have the good label, can reach the grafana.
+ ## But sometimes, we want the grafana to be accessible to clients from other namespaces, in this case, we can use this
+ ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added.
+ ##
+ ## Example:
+ ## explicitNamespacesSelector:
+ ## matchLabels:
+ ## role: frontend
+ ## matchExpressions:
+ ## - {key: role, operator: In, values: [frontend]}
+ ##
+ explicitNamespacesSelector: {}
+ ##
+ ##
+ ##
+ ##
+ ##
+ ##
+ egress:
+ ## @param networkPolicy.egress.enabled When enabled, an egress network policy will be
+ ## created allowing grafana to connect to external data sources from kubernetes cluster.
+ enabled: false
+ ##
+ ## @param networkPolicy.egress.ports Add individual ports to be allowed by the egress
+ ports: []
+ ## Add ports to the egress by specifying - port:
+ ## E.X.
+ ## ports:
+ ## - port: 80
+ ## - port: 443
+ ##
+ ##
+ ##
+ ##
+ ##
+ ##
+
+# Enable backward compatibility of kubernetes where version below 1.13 doesn't have the enableServiceLinks option
+enableKubeBackwardCompatibility: false
+useStatefulSet: false
+# Create a dynamic manifests via values:
+extraObjects: []
+ # - apiVersion: "kubernetes-client.io/v1"
+ # kind: ExternalSecret
+ # metadata:
+ # name: grafana-secrets
+ # spec:
+ # backendType: gcpSecretsManager
+ # data:
+ # - key: grafana-admin-password
+ # name: adminPassword
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/.helmignore b/kube-prometheus-stack/charts/kube-state-metrics/.helmignore
new file mode 100644
index 00000000..f0c13194
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/.helmignore
@@ -0,0 +1,21 @@
+# 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
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/Chart.yaml b/kube-prometheus-stack/charts/kube-state-metrics/Chart.yaml
new file mode 100644
index 00000000..6ff3e2e4
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/Chart.yaml
@@ -0,0 +1,21 @@
+apiVersion: v2
+appVersion: 2.6.0
+description: Install kube-state-metrics to generate and expose cluster-level metrics
+home: https://github.com/kubernetes/kube-state-metrics/
+keywords:
+- metric
+- monitoring
+- prometheus
+- kubernetes
+maintainers:
+- email: tariq.ibrahim@mulesoft.com
+ name: tariq1890
+- email: manuel@rueg.eu
+ name: mrueg
+- email: davidcalvertfr@gmail.com
+ name: dotdc
+name: kube-state-metrics
+sources:
+- https://github.com/kubernetes/kube-state-metrics/
+type: application
+version: 4.20.2
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/README.md b/kube-prometheus-stack/charts/kube-state-metrics/README.md
new file mode 100644
index 00000000..7c2e1691
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/README.md
@@ -0,0 +1,68 @@
+# kube-state-metrics Helm Chart
+
+Installs the [kube-state-metrics agent](https://github.com/kubernetes/kube-state-metrics).
+
+## Get Repo Info
+
+```console
+helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
+helm repo update
+```
+
+_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._
+
+## Install Chart
+
+```console
+helm install [RELEASE_NAME] prometheus-community/kube-state-metrics [flags]
+```
+
+_See [configuration](#configuration) below._
+
+_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._
+
+## Uninstall Chart
+
+```console
+helm uninstall [RELEASE_NAME]
+```
+
+This removes all the Kubernetes components associated with the chart and deletes the release.
+
+_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._
+
+## Upgrading Chart
+
+```console
+helm upgrade [RELEASE_NAME] prometheus-community/kube-state-metrics [flags]
+```
+
+_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._
+
+### Migrating from stable/kube-state-metrics and kubernetes/kube-state-metrics
+
+You can upgrade in-place:
+
+1. [get repo info](#get-repo-info)
+1. [upgrade](#upgrading-chart) your existing release name using the new chart repo
+
+
+## Upgrading to v3.0.0
+
+v3.0.0 includes kube-state-metrics v2.0, see the [changelog](https://github.com/kubernetes/kube-state-metrics/blob/release-2.0/CHANGELOG.md) for major changes on the application-side.
+
+The upgraded chart now the following changes:
+* Dropped support for helm v2 (helm v3 or later is required)
+* collectors key was renamed to resources
+* namespace key was renamed to namespaces
+
+
+## Configuration
+
+See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). To see all configurable options with detailed comments:
+
+```console
+helm show values prometheus-community/kube-state-metrics
+```
+
+You may also run `helm show values` on this chart's [dependencies](#dependencies) for additional options.
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/NOTES.txt b/kube-prometheus-stack/charts/kube-state-metrics/templates/NOTES.txt
new file mode 100644
index 00000000..5a646e0c
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/NOTES.txt
@@ -0,0 +1,10 @@
+kube-state-metrics is a simple service that listens to the Kubernetes API server and generates metrics about the state of the objects.
+The exposed metrics can be found here:
+https://github.com/kubernetes/kube-state-metrics/blob/master/docs/README.md#exposed-metrics
+
+The metrics are exported on the HTTP endpoint /metrics on the listening port.
+In your case, {{ template "kube-state-metrics.fullname" . }}.{{ template "kube-state-metrics.namespace" . }}.svc.cluster.local:{{ .Values.service.port }}/metrics
+
+They are served either as plaintext or protobuf depending on the Accept header.
+They are designed to be consumed either by Prometheus itself or by a scraper that is compatible with scraping a Prometheus client endpoint.
+
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/_helpers.tpl b/kube-prometheus-stack/charts/kube-state-metrics/templates/_helpers.tpl
new file mode 100644
index 00000000..976b2733
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/_helpers.tpl
@@ -0,0 +1,82 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "kube-state-metrics.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 "kube-state-metrics.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 the name of the service account to use
+*/}}
+{{- define "kube-state-metrics.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+ {{ default (include "kube-state-metrics.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+ {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Allow the release namespace to be overridden for multi-namespace deployments in combined charts
+*/}}
+{{- define "kube-state-metrics.namespace" -}}
+ {{- if .Values.namespaceOverride -}}
+ {{- .Values.namespaceOverride -}}
+ {{- else -}}
+ {{- .Release.Namespace -}}
+ {{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "kube-state-metrics.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Generate basic labels
+*/}}
+{{- define "kube-state-metrics.labels" }}
+helm.sh/chart: {{ template "kube-state-metrics.chart" . }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+app.kubernetes.io/component: metrics
+app.kubernetes.io/part-of: {{ template "kube-state-metrics.name" . }}
+{{- include "kube-state-metrics.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+{{- if .Values.customLabels }}
+{{ toYaml .Values.customLabels }}
+{{- end }}
+{{- if .Values.releaseLabel }}
+release: {{ .Release.Name }}
+{{- end }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "kube-state-metrics.selectorLabels" }}
+app.kubernetes.io/name: {{ include "kube-state-metrics.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/clusterrolebinding.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/clusterrolebinding.yaml
new file mode 100644
index 00000000..cf9f628d
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/clusterrolebinding.yaml
@@ -0,0 +1,20 @@
+{{- if and .Values.rbac.create .Values.rbac.useClusterRole -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+ name: {{ template "kube-state-metrics.fullname" . }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+{{- if .Values.rbac.useExistingRole }}
+ name: {{ .Values.rbac.useExistingRole }}
+{{- else }}
+ name: {{ template "kube-state-metrics.fullname" . }}
+{{- end }}
+subjects:
+- kind: ServiceAccount
+ name: {{ template "kube-state-metrics.serviceAccountName" . }}
+ namespace: {{ template "kube-state-metrics.namespace" . }}
+{{- end -}}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/deployment.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/deployment.yaml
new file mode 100644
index 00000000..e529d3fc
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/deployment.yaml
@@ -0,0 +1,179 @@
+apiVersion: apps/v1
+{{- if .Values.autosharding.enabled }}
+kind: StatefulSet
+{{- else }}
+kind: Deployment
+{{- end }}
+metadata:
+ name: {{ template "kube-state-metrics.fullname" . }}
+ namespace: {{ template "kube-state-metrics.namespace" . }}
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+ {{- if .Values.annotations }}
+ annotations:
+{{ toYaml .Values.annotations | indent 4 }}
+ {{- end }}
+spec:
+ selector:
+ matchLabels:
+ {{- include "kube-state-metrics.selectorLabels" . | indent 6 }}
+ replicas: {{ .Values.replicas }}
+ {{- if .Values.autosharding.enabled }}
+ serviceName: {{ template "kube-state-metrics.fullname" . }}
+ volumeClaimTemplates: []
+ {{- end }}
+ template:
+ metadata:
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 8 }}
+ {{- if .Values.podAnnotations }}
+ annotations:
+{{ toYaml .Values.podAnnotations | indent 8 }}
+ {{- end }}
+ spec:
+ hostNetwork: {{ .Values.hostNetwork }}
+ serviceAccountName: {{ template "kube-state-metrics.serviceAccountName" . }}
+ {{- if .Values.securityContext.enabled }}
+ securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 8 }}
+ {{- end }}
+ {{- if .Values.priorityClassName }}
+ priorityClassName: {{ .Values.priorityClassName }}
+ {{- end }}
+ containers:
+ - name: {{ template "kube-state-metrics.name" . }}
+ {{- if .Values.autosharding.enabled }}
+ env:
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ - name: POD_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ {{- end }}
+ args:
+ {{- if .Values.extraArgs }}
+ {{- .Values.extraArgs | toYaml | nindent 8 }}
+ {{- end }}
+ {{- if .Values.service.port }}
+ - --port={{ .Values.service.port | default 8080}}
+ {{- end }}
+ {{- if .Values.collectors }}
+ - --resources={{ .Values.collectors | join "," }}
+ {{- end }}
+ {{- if .Values.metricLabelsAllowlist }}
+ - --metric-labels-allowlist={{ .Values.metricLabelsAllowlist | join "," }}
+ {{- end }}
+ {{- if .Values.metricAnnotationsAllowList }}
+ - --metric-annotations-allowlist={{ .Values.metricAnnotationsAllowList | join "," }}
+ {{- end }}
+ {{- if .Values.metricAllowlist }}
+ - --metric-allowlist={{ .Values.metricAllowlist | join "," }}
+ {{- end }}
+ {{- if .Values.metricDenylist }}
+ - --metric-denylist={{ .Values.metricDenylist | join "," }}
+ {{- end }}
+ {{- $namespaces := list }}
+ {{- if .Values.namespaces }}
+ {{- range $ns := join "," .Values.namespaces | split "," }}
+ {{- $namespaces = append $namespaces (tpl $ns $) }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.releaseNamespace }}
+ {{- $namespaces = append $namespaces ( include "kube-state-metrics.namespace" . ) }}
+ {{- end }}
+ {{- if $namespaces }}
+ - --namespaces={{ $namespaces | mustUniq | join "," }}
+ {{- end }}
+ {{- if .Values.namespacesDenylist }}
+ - --namespaces-denylist={{ tpl (.Values.namespacesDenylist | join ",") $ }}
+ {{- end }}
+ {{- if .Values.autosharding.enabled }}
+ - --pod=$(POD_NAME)
+ - --pod-namespace=$(POD_NAMESPACE)
+ {{- end }}
+ {{- if .Values.kubeconfig.enabled }}
+ - --kubeconfig=/opt/k8s/.kube/config
+ {{- end }}
+ {{- if .Values.selfMonitor.telemetryHost }}
+ - --telemetry-host={{ .Values.selfMonitor.telemetryHost }}
+ {{- end }}
+ {{- if .Values.selfMonitor.telemetryPort }}
+ - --telemetry-port={{ .Values.selfMonitor.telemetryPort | default 8081 }}
+ {{- end }}
+ {{- if or (.Values.kubeconfig.enabled) (.Values.volumeMounts) }}
+ volumeMounts:
+ {{- if .Values.kubeconfig.enabled }}
+ - name: kubeconfig
+ mountPath: /opt/k8s/.kube/
+ readOnly: true
+ {{- end }}
+ {{- if .Values.volumeMounts }}
+{{ toYaml .Values.volumeMounts | indent 8 }}
+ {{- end }}
+ {{- end }}
+ imagePullPolicy: {{ .Values.image.pullPolicy }}
+ {{- if .Values.image.sha }}
+ image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}@sha256:{{ .Values.image.sha }}"
+ {{- else }}
+ image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+ {{- end }}
+ ports:
+ - containerPort: {{ .Values.service.port | default 8080}}
+ name: "http"
+ {{- if .Values.selfMonitor.enabled }}
+ - containerPort: {{ .Values.selfMonitor.telemetryPort | default 8081 }}
+ name: "metrics"
+ {{- end }}
+ livenessProbe:
+ httpGet:
+ path: /healthz
+ port: {{ .Values.service.port | default 8080}}
+ initialDelaySeconds: 5
+ timeoutSeconds: 5
+ readinessProbe:
+ httpGet:
+ path: /
+ port: {{ .Values.service.port | default 8080}}
+ initialDelaySeconds: 5
+ timeoutSeconds: 5
+ {{- if .Values.resources }}
+ resources:
+{{ toYaml .Values.resources | indent 10 }}
+{{- end }}
+{{- if .Values.containerSecurityContext }}
+ securityContext:
+{{ toYaml .Values.containerSecurityContext | indent 10 }}
+{{- end }}
+{{- if .Values.imagePullSecrets }}
+ imagePullSecrets:
+{{ toYaml .Values.imagePullSecrets | indent 8 }}
+ {{- end }}
+ {{- if .Values.affinity }}
+ affinity:
+{{ toYaml .Values.affinity | indent 8 }}
+ {{- end }}
+ {{- if .Values.nodeSelector }}
+ nodeSelector:
+{{ toYaml .Values.nodeSelector | indent 8 }}
+ {{- end }}
+ {{- if .Values.tolerations }}
+ tolerations:
+{{ toYaml .Values.tolerations | indent 8 }}
+ {{- end }}
+ {{- if .Values.topologySpreadConstraints }}
+ topologySpreadConstraints:
+{{ toYaml .Values.topologySpreadConstraints | indent 8 }}
+ {{- end }}
+ {{- if or (.Values.kubeconfig.enabled) (.Values.volumes) }}
+ volumes:
+ {{- if .Values.kubeconfig.enabled}}
+ - name: kubeconfig
+ secret:
+ secretName: {{ template "kube-state-metrics.fullname" . }}-kubeconfig
+ {{- end }}
+ {{- if .Values.volumes }}
+{{ toYaml .Values.volumes | indent 8 }}
+ {{- end }}
+ {{- end }}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/kubeconfig-secret.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/kubeconfig-secret.yaml
new file mode 100644
index 00000000..6af00845
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/kubeconfig-secret.yaml
@@ -0,0 +1,12 @@
+{{- if .Values.kubeconfig.enabled -}}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ template "kube-state-metrics.fullname" . }}-kubeconfig
+ namespace: {{ template "kube-state-metrics.namespace" . }}
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+type: Opaque
+data:
+ config: '{{ .Values.kubeconfig.secret }}'
+{{- end -}}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/pdb.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/pdb.yaml
new file mode 100644
index 00000000..3771b511
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/pdb.yaml
@@ -0,0 +1,18 @@
+{{- if .Values.podDisruptionBudget -}}
+{{ if $.Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" -}}
+apiVersion: policy/v1
+{{- else -}}
+apiVersion: policy/v1beta1
+{{- end }}
+kind: PodDisruptionBudget
+metadata:
+ name: {{ template "kube-state-metrics.fullname" . }}
+ namespace: {{ template "kube-state-metrics.namespace" . }}
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+spec:
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }}
+{{ toYaml .Values.podDisruptionBudget | indent 2 }}
+{{- end -}}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/podsecuritypolicy.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/podsecuritypolicy.yaml
new file mode 100644
index 00000000..3299056a
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/podsecuritypolicy.yaml
@@ -0,0 +1,39 @@
+{{- if .Values.podSecurityPolicy.enabled }}
+apiVersion: policy/v1beta1
+kind: PodSecurityPolicy
+metadata:
+ name: {{ template "kube-state-metrics.fullname" . }}
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+{{- if .Values.podSecurityPolicy.annotations }}
+ annotations:
+{{ toYaml .Values.podSecurityPolicy.annotations | indent 4 }}
+{{- end }}
+spec:
+ privileged: false
+ volumes:
+ - 'secret'
+{{- if .Values.podSecurityPolicy.additionalVolumes }}
+{{ toYaml .Values.podSecurityPolicy.additionalVolumes | indent 4 }}
+{{- end }}
+ hostNetwork: false
+ hostIPC: false
+ hostPID: false
+ runAsUser:
+ rule: 'MustRunAsNonRoot'
+ seLinux:
+ rule: 'RunAsAny'
+ supplementalGroups:
+ rule: 'MustRunAs'
+ ranges:
+ # Forbid adding the root group.
+ - min: 1
+ max: 65535
+ fsGroup:
+ rule: 'MustRunAs'
+ ranges:
+ # Forbid adding the root group.
+ - min: 1
+ max: 65535
+ readOnlyRootFilesystem: false
+{{- end }}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/psp-clusterrole.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/psp-clusterrole.yaml
new file mode 100644
index 00000000..69047d4f
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/psp-clusterrole.yaml
@@ -0,0 +1,19 @@
+{{- if and .Values.podSecurityPolicy.enabled .Values.rbac.create -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+ name: psp-{{ template "kube-state-metrics.fullname" . }}
+rules:
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if semverCompare "> 1.15.0-0" $kubeTargetVersion }}
+- apiGroups: ['policy']
+{{- else }}
+- apiGroups: ['extensions']
+{{- end }}
+ resources: ['podsecuritypolicies']
+ verbs: ['use']
+ resourceNames:
+ - {{ template "kube-state-metrics.fullname" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml
new file mode 100644
index 00000000..03c56d57
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml
@@ -0,0 +1,16 @@
+{{- if and .Values.podSecurityPolicy.enabled .Values.rbac.create -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+ name: psp-{{ template "kube-state-metrics.fullname" . }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: psp-{{ template "kube-state-metrics.fullname" . }}
+subjects:
+ - kind: ServiceAccount
+ name: {{ template "kube-state-metrics.serviceAccountName" . }}
+ namespace: {{ template "kube-state-metrics.namespace" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/role.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/role.yaml
new file mode 100644
index 00000000..e3275140
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/role.yaml
@@ -0,0 +1,190 @@
+{{- if and (eq .Values.rbac.create true) (not .Values.rbac.useExistingRole) -}}
+{{- range (ternary (join "," .Values.namespaces | split "," ) (list "") (eq $.Values.rbac.useClusterRole false)) }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+{{- if eq $.Values.rbac.useClusterRole false }}
+kind: Role
+{{- else }}
+kind: ClusterRole
+{{- end }}
+metadata:
+ labels:
+ {{- include "kube-state-metrics.labels" $ | indent 4 }}
+ name: {{ template "kube-state-metrics.fullname" $ }}
+{{- if eq $.Values.rbac.useClusterRole false }}
+ namespace: {{ . }}
+{{- end }}
+rules:
+{{ if has "certificatesigningrequests" $.Values.collectors }}
+- apiGroups: ["certificates.k8s.io"]
+ resources:
+ - certificatesigningrequests
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "configmaps" $.Values.collectors }}
+- apiGroups: [""]
+ resources:
+ - configmaps
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "cronjobs" $.Values.collectors }}
+- apiGroups: ["batch"]
+ resources:
+ - cronjobs
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "daemonsets" $.Values.collectors }}
+- apiGroups: ["extensions", "apps"]
+ resources:
+ - daemonsets
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "deployments" $.Values.collectors }}
+- apiGroups: ["extensions", "apps"]
+ resources:
+ - deployments
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "endpoints" $.Values.collectors }}
+- apiGroups: [""]
+ resources:
+ - endpoints
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "horizontalpodautoscalers" $.Values.collectors }}
+- apiGroups: ["autoscaling"]
+ resources:
+ - horizontalpodautoscalers
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "ingresses" $.Values.collectors }}
+- apiGroups: ["extensions", "networking.k8s.io"]
+ resources:
+ - ingresses
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "jobs" $.Values.collectors }}
+- apiGroups: ["batch"]
+ resources:
+ - jobs
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "limitranges" $.Values.collectors }}
+- apiGroups: [""]
+ resources:
+ - limitranges
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "mutatingwebhookconfigurations" $.Values.collectors }}
+- apiGroups: ["admissionregistration.k8s.io"]
+ resources:
+ - mutatingwebhookconfigurations
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "namespaces" $.Values.collectors }}
+- apiGroups: [""]
+ resources:
+ - namespaces
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "networkpolicies" $.Values.collectors }}
+- apiGroups: ["networking.k8s.io"]
+ resources:
+ - networkpolicies
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "nodes" $.Values.collectors }}
+- apiGroups: [""]
+ resources:
+ - nodes
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "persistentvolumeclaims" $.Values.collectors }}
+- apiGroups: [""]
+ resources:
+ - persistentvolumeclaims
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "persistentvolumes" $.Values.collectors }}
+- apiGroups: [""]
+ resources:
+ - persistentvolumes
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "poddisruptionbudgets" $.Values.collectors }}
+- apiGroups: ["policy"]
+ resources:
+ - poddisruptionbudgets
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "pods" $.Values.collectors }}
+- apiGroups: [""]
+ resources:
+ - pods
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "replicasets" $.Values.collectors }}
+- apiGroups: ["extensions", "apps"]
+ resources:
+ - replicasets
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "replicationcontrollers" $.Values.collectors }}
+- apiGroups: [""]
+ resources:
+ - replicationcontrollers
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "resourcequotas" $.Values.collectors }}
+- apiGroups: [""]
+ resources:
+ - resourcequotas
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "secrets" $.Values.collectors }}
+- apiGroups: [""]
+ resources:
+ - secrets
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "services" $.Values.collectors }}
+- apiGroups: [""]
+ resources:
+ - services
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "statefulsets" $.Values.collectors }}
+- apiGroups: ["apps"]
+ resources:
+ - statefulsets
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "storageclasses" $.Values.collectors }}
+- apiGroups: ["storage.k8s.io"]
+ resources:
+ - storageclasses
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "validatingwebhookconfigurations" $.Values.collectors }}
+- apiGroups: ["admissionregistration.k8s.io"]
+ resources:
+ - validatingwebhookconfigurations
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "volumeattachments" $.Values.collectors }}
+- apiGroups: ["storage.k8s.io"]
+ resources:
+ - volumeattachments
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if has "verticalpodautoscalers" $.Values.collectors }}
+- apiGroups: ["autoscaling.k8s.io"]
+ resources:
+ - verticalpodautoscalers
+ verbs: ["list", "watch"]
+{{ end -}}
+{{ if $.Values.rbac.extraRules }}
+{{ toYaml $.Values.rbac.extraRules }}
+{{ end }}
+{{- end -}}
+{{- end -}}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/rolebinding.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/rolebinding.yaml
new file mode 100644
index 00000000..330651b7
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/rolebinding.yaml
@@ -0,0 +1,24 @@
+{{- if and (eq .Values.rbac.create true) (eq .Values.rbac.useClusterRole false) -}}
+{{- range (join "," $.Values.namespaces) | split "," }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ labels:
+ {{- include "kube-state-metrics.labels" $ | indent 4 }}
+ name: {{ template "kube-state-metrics.fullname" $ }}
+ namespace: {{ . }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+{{- if (not $.Values.rbac.useExistingRole) }}
+ name: {{ template "kube-state-metrics.fullname" $ }}
+{{- else }}
+ name: {{ $.Values.rbac.useExistingRole }}
+{{- end }}
+subjects:
+- kind: ServiceAccount
+ name: {{ template "kube-state-metrics.serviceAccountName" $ }}
+ namespace: {{ template "kube-state-metrics.namespace" $ }}
+{{- end -}}
+{{- end -}}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/service.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/service.yaml
new file mode 100644
index 00000000..92c6d4fc
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/service.yaml
@@ -0,0 +1,41 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-state-metrics.fullname" . }}
+ namespace: {{ template "kube-state-metrics.namespace" . }}
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+ annotations:
+ {{- if .Values.prometheusScrape }}
+ prometheus.io/scrape: '{{ .Values.prometheusScrape }}'
+ {{- end }}
+ {{- if .Values.service.annotations }}
+ {{- toYaml .Values.service.annotations | nindent 4 }}
+ {{- end }}
+spec:
+ type: "{{ .Values.service.type }}"
+ ports:
+ - name: "http"
+ protocol: TCP
+ port: {{ .Values.service.port | default 8080}}
+ {{- if .Values.service.nodePort }}
+ nodePort: {{ .Values.service.nodePort }}
+ {{- end }}
+ targetPort: {{ .Values.service.port | default 8080}}
+ {{ if .Values.selfMonitor.enabled }}
+ - name: "metrics"
+ protocol: TCP
+ port: {{ .Values.selfMonitor.telemetryPort | default 8081 }}
+ targetPort: {{ .Values.selfMonitor.telemetryPort | default 8081 }}
+ {{- if .Values.selfMonitor.telemetryNodePort }}
+ nodePort: {{ .Values.selfMonitor.telemetryNodePort }}
+ {{- end }}
+ {{ end }}
+{{- if .Values.service.loadBalancerIP }}
+ loadBalancerIP: "{{ .Values.service.loadBalancerIP }}"
+{{- end }}
+{{- if .Values.service.clusterIP }}
+ clusterIP: "{{ .Values.service.clusterIP }}"
+{{- end }}
+ selector:
+ {{- include "kube-state-metrics.selectorLabels" . | indent 4 }}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/serviceaccount.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/serviceaccount.yaml
new file mode 100644
index 00000000..e1229eb9
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/serviceaccount.yaml
@@ -0,0 +1,15 @@
+{{- if .Values.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+ name: {{ template "kube-state-metrics.serviceAccountName" . }}
+ namespace: {{ template "kube-state-metrics.namespace" . }}
+{{- if .Values.serviceAccount.annotations }}
+ annotations:
+{{ toYaml .Values.serviceAccount.annotations | indent 4 }}
+{{- end }}
+imagePullSecrets:
+{{ toYaml .Values.serviceAccount.imagePullSecrets | indent 2 }}
+{{- end -}}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/servicemonitor.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/servicemonitor.yaml
new file mode 100644
index 00000000..4deac955
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/servicemonitor.yaml
@@ -0,0 +1,80 @@
+{{- if .Values.prometheus.monitor.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-state-metrics.fullname" . }}
+ namespace: {{ template "kube-state-metrics.namespace" . }}
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+ {{- with .Values.prometheus.monitor.additionalLabels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ jobLabel: {{ default "app.kubernetes.io/name" .Values.prometheus.monitor.jobLabel }}
+ selector:
+ matchLabels:
+ {{- if .Values.prometheus.monitor.selectorOverride -}}
+ {{ toYaml .Values.prometheus.monitor.selectorOverride | nindent 6 }}
+ {{ else }}
+ {{- include "kube-state-metrics.selectorLabels" . | indent 6 }}
+ {{- end }}
+ endpoints:
+ - port: http
+ {{- if .Values.prometheus.monitor.interval }}
+ interval: {{ .Values.prometheus.monitor.interval }}
+ {{- end }}
+ {{- if .Values.prometheus.monitor.scrapeTimeout }}
+ scrapeTimeout: {{ .Values.prometheus.monitor.scrapeTimeout }}
+ {{- end }}
+ {{- if .Values.prometheus.monitor.proxyUrl }}
+ proxyUrl: {{ .Values.prometheus.monitor.proxyUrl}}
+ {{- end }}
+ {{- if .Values.prometheus.monitor.honorLabels }}
+ honorLabels: true
+ {{- end }}
+ {{- if .Values.prometheus.monitor.metricRelabelings }}
+ metricRelabelings:
+ {{- toYaml .Values.prometheus.monitor.metricRelabelings | nindent 8 }}
+ {{- end }}
+ {{- if .Values.prometheus.monitor.relabelings }}
+ relabelings:
+ {{- toYaml .Values.prometheus.monitor.relabelings | nindent 8 }}
+ {{- end }}
+ {{- if .Values.prometheus.monitor.scheme }}
+ scheme: {{ .Values.prometheus.monitor.scheme }}
+ {{- end }}
+ {{- if .Values.prometheus.monitor.tlsConfig }}
+ tlsConfig:
+ {{- toYaml .Values.prometheus.monitor.tlsConfig | nindent 8 }}
+ {{- end }}
+ {{- if .Values.selfMonitor.enabled }}
+ - port: metrics
+ {{- if .Values.prometheus.monitor.interval }}
+ interval: {{ .Values.prometheus.monitor.interval }}
+ {{- end }}
+ {{- if .Values.prometheus.monitor.scrapeTimeout }}
+ scrapeTimeout: {{ .Values.prometheus.monitor.scrapeTimeout }}
+ {{- end }}
+ {{- if .Values.prometheus.monitor.proxyUrl }}
+ proxyUrl: {{ .Values.prometheus.monitor.proxyUrl}}
+ {{- end }}
+ {{- if .Values.prometheus.monitor.honorLabels }}
+ honorLabels: true
+ {{- end }}
+ {{- if .Values.prometheus.monitor.metricRelabelings }}
+ metricRelabelings:
+ {{- toYaml .Values.prometheus.monitor.metricRelabelings | nindent 8 }}
+ {{- end }}
+ {{- if .Values.prometheus.monitor.relabelings }}
+ relabelings:
+ {{- toYaml .Values.prometheus.monitor.relabelings | nindent 8 }}
+ {{- end }}
+ {{- if .Values.prometheus.monitor.scheme }}
+ scheme: {{ .Values.prometheus.monitor.scheme }}
+ {{- end }}
+ {{- if .Values.prometheus.monitor.tlsConfig }}
+ tlsConfig:
+ {{- toYaml .Values.prometheus.monitor.tlsConfig | nindent 8 }}
+ {{- end }}
+ {{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/stsdiscovery-role.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/stsdiscovery-role.yaml
new file mode 100644
index 00000000..489de147
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/stsdiscovery-role.yaml
@@ -0,0 +1,26 @@
+{{- if and .Values.autosharding.enabled .Values.rbac.create -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: stsdiscovery-{{ template "kube-state-metrics.fullname" . }}
+ namespace: {{ template "kube-state-metrics.namespace" . }}
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+rules:
+- apiGroups:
+ - ""
+ resources:
+ - pods
+ verbs:
+ - get
+- apiGroups:
+ - apps
+ resourceNames:
+ - {{ template "kube-state-metrics.fullname" . }}
+ resources:
+ - statefulsets
+ verbs:
+ - get
+ - list
+ - watch
+{{- end }}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml
new file mode 100644
index 00000000..73b37a4f
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml
@@ -0,0 +1,17 @@
+{{- if and .Values.autosharding.enabled .Values.rbac.create -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: stsdiscovery-{{ template "kube-state-metrics.fullname" . }}
+ namespace: {{ template "kube-state-metrics.namespace" . }}
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: stsdiscovery-{{ template "kube-state-metrics.fullname" . }}
+subjects:
+ - kind: ServiceAccount
+ name: {{ template "kube-state-metrics.serviceAccountName" . }}
+ namespace: {{ template "kube-state-metrics.namespace" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/templates/verticalpodautoscaler.yaml b/kube-prometheus-stack/charts/kube-state-metrics/templates/verticalpodautoscaler.yaml
new file mode 100644
index 00000000..e825e5c8
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/templates/verticalpodautoscaler.yaml
@@ -0,0 +1,34 @@
+{{- if and (.Capabilities.APIVersions.Has "autoscaling.k8s.io/v1") (.Values.verticalPodAutoscaler.enabled) }}
+apiVersion: autoscaling.k8s.io/v1
+kind: VerticalPodAutoscaler
+metadata:
+ name: {{ template "kube-state-metrics.fullname" . }}
+ namespace: {{ template "kube-state-metrics.namespace" . }}
+ labels:
+ {{- include "kube-state-metrics.labels" . | indent 4 }}
+spec:
+ resourcePolicy:
+ containerPolicies:
+ - containerName: {{ template "kube-state-metrics.name" . }}
+ {{- if .Values.verticalPodAutoscaler.controlledResources }}
+ controlledResources: {{ .Values.verticalPodAutoscaler.controlledResources }}
+ {{- end }}
+ {{- if .Values.verticalPodAutoscaler.maxAllowed }}
+ maxAllowed:
+ {{ toYaml .Values.verticalPodAutoscaler.maxAllowed | nindent 8 }}
+ {{- end }}
+ {{- if .Values.verticalPodAutoscaler.minAllowed }}
+ minAllowed:
+ {{ toYaml .Values.verticalPodAutoscaler.minAllowed | nindent 8 }}
+ {{- end }}
+ targetRef:
+ apiVersion: apps/v1
+ kind: Deployment
+ name: {{ template "kube-state-metrics.fullname" . }}
+ {{- if .Values.verticalPodAutoscaler.updatePolicy }}
+ updatePolicy:
+ {{- if .Values.verticalPodAutoscaler.updatePolicy.updateMode }}
+ updateMode: {{ .Values.verticalPodAutoscaler.updatePolicy.updateMode }}
+ {{- end }}
+ {{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/kube-state-metrics/values.yaml b/kube-prometheus-stack/charts/kube-state-metrics/values.yaml
new file mode 100644
index 00000000..fb35dd72
--- /dev/null
+++ b/kube-prometheus-stack/charts/kube-state-metrics/values.yaml
@@ -0,0 +1,285 @@
+# Default values for kube-state-metrics.
+prometheusScrape: true
+image:
+ repository: registry.k8s.io/kube-state-metrics/kube-state-metrics
+ tag: v2.6.0
+ sha: ""
+ pullPolicy: IfNotPresent
+
+imagePullSecrets: []
+# - name: "image-pull-secret"
+
+# If set to true, this will deploy kube-state-metrics as a StatefulSet and the data
+# will be automatically sharded across <.Values.replicas> pods using the built-in
+# autodiscovery feature: https://github.com/kubernetes/kube-state-metrics#automated-sharding
+# This is an experimental feature and there are no stability guarantees.
+autosharding:
+ enabled: false
+
+replicas: 1
+
+# List of additional cli arguments to configure kube-state-metrics
+# for example: --enable-gzip-encoding, --log-file, etc.
+# all the possible args can be found here: https://github.com/kubernetes/kube-state-metrics/blob/master/docs/cli-arguments.md
+extraArgs: []
+
+service:
+ port: 8080
+ # Default to clusterIP for backward compatibility
+ type: ClusterIP
+ nodePort: 0
+ loadBalancerIP: ""
+ clusterIP: ""
+ annotations: {}
+
+## Additional labels to add to all resources
+customLabels: {}
+ # app: kube-state-metrics
+
+## set to true to add the release label so scraping of the servicemonitor with kube-prometheus-stack works out of the box
+releaseLabel: false
+
+hostNetwork: false
+
+rbac:
+ # If true, create & use RBAC resources
+ create: true
+
+ # Set to a rolename to use existing role - skipping role creating - but still doing serviceaccount and rolebinding to it, rolename set here.
+ # useExistingRole: your-existing-role
+
+ # If set to false - Run without Cluteradmin privs needed - ONLY works if namespace is also set (if useExistingRole is set this name is used as ClusterRole or Role to bind to)
+ useClusterRole: true
+
+ # Add permissions for CustomResources' apiGroups in Role/ClusterRole. Should be used in conjunction with Custom Resource State Metrics configuration
+ # Example:
+ # - apiGroups: ["monitoring.coreos.com"]
+ # resources: ["prometheuses"]
+ # verbs: ["list", "watch"]
+ extraRules: []
+
+serviceAccount:
+ # Specifies whether a ServiceAccount should be created, require rbac true
+ 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:
+ # Reference to one or more secrets to be used when pulling images
+ # ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
+ imagePullSecrets: []
+ # ServiceAccount annotations.
+ # Use case: AWS EKS IAM roles for service accounts
+ # ref: https://docs.aws.amazon.com/eks/latest/userguide/specify-service-account-role.html
+ annotations: {}
+
+prometheus:
+ monitor:
+ enabled: false
+ additionalLabels: {}
+ namespace: ""
+ jobLabel: ""
+ interval: ""
+ scrapeTimeout: ""
+ proxyUrl: ""
+ selectorOverride: {}
+ honorLabels: false
+ metricRelabelings: []
+ relabelings: []
+ scheme: ""
+ tlsConfig: {}
+
+## Specify if a Pod Security Policy for kube-state-metrics must be created
+## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/
+##
+podSecurityPolicy:
+ enabled: false
+ annotations: {}
+ ## Specify pod annotations
+ ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#apparmor
+ ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp
+ ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#sysctl
+ ##
+ # seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
+ # seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
+ # apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
+
+ additionalVolumes: []
+
+securityContext:
+ enabled: true
+ runAsGroup: 65534
+ runAsUser: 65534
+ fsGroup: 65534
+
+## Specify security settings for a Container
+## Allows overrides and additional options compared to (Pod) securityContext
+## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container
+containerSecurityContext: {}
+
+## Node labels for pod assignment
+## Ref: https://kubernetes.io/docs/user-guide/node-selection/
+nodeSelector: {}
+
+## Affinity settings for pod assignment
+## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
+affinity: {}
+
+## Tolerations for pod assignment
+## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+tolerations: []
+
+## Topology spread constraints for pod assignment
+## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
+topologySpreadConstraints: []
+
+# Annotations to be added to the deployment/statefulset
+annotations: {}
+
+# Annotations to be added to the pod
+podAnnotations: {}
+
+## Assign a PriorityClassName to pods if set
+# priorityClassName: ""
+
+# Ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/
+podDisruptionBudget: {}
+
+# Comma-separated list of metrics to be exposed.
+# This list comprises of exact metric names and/or regex patterns.
+# The allowlist and denylist are mutually exclusive.
+metricAllowlist: []
+
+# Comma-separated list of metrics not to be enabled.
+# This list comprises of exact metric names and/or regex patterns.
+# The allowlist and denylist are mutually exclusive.
+metricDenylist: []
+
+# Comma-separated list of additional Kubernetes label keys that will be used in the resource's
+# labels metric. By default the metric contains only name and namespace labels.
+# To include additional labels, provide a list of resource names in their plural form and Kubernetes
+# label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'.
+# A single '*' can be provided per resource instead to allow any labels, but that has
+# severe performance implications (Example: '=pods=[*]').
+metricLabelsAllowlist: []
+ # - namespaces=[k8s-label-1,k8s-label-n]
+
+# Comma-separated list of Kubernetes annotations keys that will be used in the resource'
+# labels metric. By default the metric contains only name and namespace labels.
+# To include additional annotations provide a list of resource names in their plural form and Kubernetes
+# annotation keys you would like to allow for them (Example: '=namespaces=[kubernetes.io/team,...],pods=[kubernetes.io/team],...)'.
+# A single '*' can be provided per resource instead to allow any annotations, but that has
+# severe performance implications (Example: '=pods=[*]').
+metricAnnotationsAllowList: []
+ # - pods=[k8s-annotation-1,k8s-annotation-n]
+
+# Available collectors for kube-state-metrics.
+# By default, all available resources are enabled, comment out to disable.
+collectors:
+ - certificatesigningrequests
+ - configmaps
+ - cronjobs
+ - daemonsets
+ - deployments
+ - endpoints
+ - horizontalpodautoscalers
+ - ingresses
+ - jobs
+ - limitranges
+ - mutatingwebhookconfigurations
+ - namespaces
+ - networkpolicies
+ - nodes
+ - persistentvolumeclaims
+ - persistentvolumes
+ - poddisruptionbudgets
+ - pods
+ - replicasets
+ - replicationcontrollers
+ - resourcequotas
+ - secrets
+ - services
+ - statefulsets
+ - storageclasses
+ - validatingwebhookconfigurations
+ - volumeattachments
+ # - verticalpodautoscalers # not a default resource, see also: https://github.com/kubernetes/kube-state-metrics#enabling-verticalpodautoscalers
+
+# Enabling kubeconfig will pass the --kubeconfig argument to the container
+kubeconfig:
+ enabled: false
+ # base64 encoded kube-config file
+ secret:
+
+# Enable only the release namespace for collecting resources. By default all namespaces are collected.
+# If releaseNamespace and namespaces are both set a merged list will be collected.
+releaseNamespace: false
+
+# Comma-separated list(string) or yaml list of namespaces to be enabled for collecting resources. By default all namespaces are collected.
+namespaces: ""
+
+# Comma-separated list of namespaces not to be enabled. If namespaces and namespaces-denylist are both set,
+# only namespaces that are excluded in namespaces-denylist will be used.
+namespacesDenylist: ""
+
+## Override the deployment namespace
+##
+namespaceOverride: ""
+
+resources: {}
+ # We usually recommend not to specify default resources and to leave this as a conscious
+ # choice for the user. This also increases chances charts run on environments with little
+ # resources, such as Minikube. If you do want to specify resources, uncomment the following
+ # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+ # limits:
+ # cpu: 100m
+ # memory: 64Mi
+ # requests:
+ # cpu: 10m
+ # memory: 32Mi
+
+## Provide a k8s version to define apiGroups for podSecurityPolicy Cluster Role.
+## For example: kubeTargetVersionOverride: 1.14.9
+##
+kubeTargetVersionOverride: ""
+
+# Enable self metrics configuration for service and Service Monitor
+# Default values for telemetry configuration can be overridden
+# If you set telemetryNodePort, you must also set service.type to NodePort
+selfMonitor:
+ enabled: false
+ # telemetryHost: 0.0.0.0
+ # telemetryPort: 8081
+ # telemetryNodePort: 0
+
+# Enable vertical pod autoscaler support for kube-state-metrics
+verticalPodAutoscaler:
+ enabled: false
+ # List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory
+ controlledResources: []
+
+ # Define the max allowed resources for the pod
+ maxAllowed: {}
+ # cpu: 200m
+ # memory: 100Mi
+ # Define the min allowed resources for the pod
+ minAllowed: {}
+ # cpu: 200m
+ # memory: 100Mi
+
+ # updatePolicy:
+ # Specifies whether recommended updates are applied when a Pod is started and whether recommended updates
+ # are applied during the life of a Pod. Possible values are "Off", "Initial", "Recreate", and "Auto".
+ # updateMode: Auto
+
+# volumeMounts are used to add custom volume mounts to deployment.
+# See example below
+volumeMounts: []
+# - mountPath: /etc/config
+# name: config-volume
+
+# volumes are used to add custom volumes to deployment
+# See example below
+volumes: []
+# - configMap:
+# name: cm-for-volume
+# name: config-volume
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/.helmignore b/kube-prometheus-stack/charts/prometheus-node-exporter/.helmignore
new file mode 100644
index 00000000..f0c13194
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/.helmignore
@@ -0,0 +1,21 @@
+# 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
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/Chart.yaml b/kube-prometheus-stack/charts/prometheus-node-exporter/Chart.yaml
new file mode 100644
index 00000000..abcba280
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/Chart.yaml
@@ -0,0 +1,18 @@
+apiVersion: v2
+appVersion: 1.3.1
+description: A Helm chart for prometheus node-exporter
+home: https://github.com/prometheus/node_exporter/
+keywords:
+- node-exporter
+- prometheus
+- exporter
+maintainers:
+- email: gianrubio@gmail.com
+ name: gianrubio
+- email: zanhsieh@gmail.com
+ name: zanhsieh
+name: prometheus-node-exporter
+sources:
+- https://github.com/prometheus/node_exporter/
+type: application
+version: 4.3.0
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/README.md b/kube-prometheus-stack/charts/prometheus-node-exporter/README.md
new file mode 100644
index 00000000..02de7b14
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/README.md
@@ -0,0 +1,77 @@
+# Prometheus `Node Exporter`
+
+Prometheus exporter for hardware and OS metrics exposed by *NIX kernels, written in Go with pluggable metric collectors.
+
+This chart bootstraps a prometheus [`Node Exporter`](http://github.com/prometheus/node_exporter) daemonset on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
+
+## Get Repository Info
+
+```console
+helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
+helm repo update
+```
+
+_See [`helm repo`](https://helm.sh/docs/helm/helm_repo/) for command documentation._
+
+## Install Chart
+
+```console
+helm install [RELEASE_NAME] prometheus-community/prometheus-node-exporter
+```
+
+_See [configuration](#configuring) below._
+
+_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._
+
+## Uninstall Chart
+
+```console
+helm uninstall [RELEASE_NAME]
+```
+
+This removes all the Kubernetes components associated with the chart and deletes the release.
+
+_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._
+
+## Upgrading Chart
+
+```console
+helm upgrade [RELEASE_NAME] [CHART] --install
+```
+
+_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._
+
+### 3.x to 4.x
+
+Starting from version 4.0.0, the `node exporter` chart is using the [Kubernetes recommended labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/). Therefore you have to delete the daemonset before you upgrade.
+
+```console
+kubectl delete daemonset -l app=prometheus-node-exporter
+helm upgrade -i prometheus-node-exporter prometheus-community/prometheus-node-exporter
+```
+
+If you use your own custom [ServiceMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitor) or [PodMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#podmonitor), please ensure to upgrade their `selector` fields accordingly to the new labels.
+
+### From 2.x to 3.x
+
+Change the following:
+
+```yaml
+hostRootFsMount: true
+```
+
+to:
+
+```yaml
+hostRootFsMount:
+ enabled: true
+ mountPropagation: HostToContainer
+```
+
+## Configuring
+
+See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). To see all configurable options with detailed comments, visit the chart's [values.yaml](./values.yaml), or run these configuration commands:
+
+```console
+helm show values prometheus-community/prometheus-node-exporter
+```
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/ci/port-values.yaml b/kube-prometheus-stack/charts/prometheus-node-exporter/ci/port-values.yaml
new file mode 100644
index 00000000..dbfb4b67
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/ci/port-values.yaml
@@ -0,0 +1,3 @@
+service:
+ targetPort: 9102
+ port: 9102
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/templates/NOTES.txt b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/NOTES.txt
new file mode 100644
index 00000000..df05e3fb
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+ export NODE_PORT=$(kubectl get --namespace {{ template "prometheus-node-exporter.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "prometheus-node-exporter.fullname" . }})
+ export NODE_IP=$(kubectl get nodes --namespace {{ template "prometheus-node-exporter.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}")
+ echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+ NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+ You can watch the status of by running 'kubectl get svc -w {{ template "prometheus-node-exporter.fullname" . }}'
+ export SERVICE_IP=$(kubectl get svc --namespace {{ template "prometheus-node-exporter.namespace" . }} {{ template "prometheus-node-exporter.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
+ echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+ export POD_NAME=$(kubectl get pods --namespace {{ template "prometheus-node-exporter.namespace" . }} -l "app.kubernetes.io/name={{ template "prometheus-node-exporter.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+ echo "Visit http://127.0.0.1:9100 to use your application"
+ kubectl port-forward --namespace {{ template "prometheus-node-exporter.namespace" . }} $POD_NAME 9100
+{{- end }}
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/templates/_helpers.tpl b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/_helpers.tpl
new file mode 100644
index 00000000..21030894
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/_helpers.tpl
@@ -0,0 +1,107 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "prometheus-node-exporter.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 "prometheus-node-exporter.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 -}}
+
+{{/* Generate basic labels */}}
+{{- define "prometheus-node-exporter.labels" }}
+helm.sh/chart: {{ template "prometheus-node-exporter.chart" . }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+app.kubernetes.io/component: metrics
+app.kubernetes.io/part-of: {{ template "prometheus-node-exporter.name" . }}
+{{- include "prometheus-node-exporter.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+{{- if .Values.podLabels}}
+{{ toYaml .Values.podLabels }}
+{{- end }}
+{{- if .Values.releaseLabel }}
+release: {{ .Release.Name }}
+{{- end }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "prometheus-node-exporter.selectorLabels" }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+app.kubernetes.io/name: {{ template "prometheus-node-exporter.name" . }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "prometheus-node-exporter.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "prometheus-node-exporter.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+ {{ default (include "prometheus-node-exporter.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+ {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
+
+{{/*
+The image to use
+*/}}
+{{- define "prometheus-node-exporter.image" -}}
+{{- if .Values.image.sha -}}
+{{- printf "%s:%s@%s" .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) .Values.image.sha }}
+{{- else -}}
+{{- printf "%s:%s" .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) }}
+{{- end }}
+{{- end }}
+
+{{/*
+Allow the release namespace to be overridden for multi-namespace deployments in combined charts
+*/}}
+{{- define "prometheus-node-exporter.namespace" -}}
+ {{- if .Values.namespaceOverride -}}
+ {{- .Values.namespaceOverride -}}
+ {{- else -}}
+ {{- .Release.Namespace -}}
+ {{- end -}}
+{{- end -}}
+
+{{/*
+Create the namespace name of the service monitor
+*/}}
+{{- define "prometheus-node-exporter.monitor-namespace" -}}
+ {{- if .Values.namespaceOverride -}}
+ {{- .Values.namespaceOverride -}}
+ {{- else -}}
+ {{- if .Values.prometheus.monitor.namespace -}}
+ {{- .Values.prometheus.monitor.namespace -}}
+ {{- else -}}
+ {{- .Release.Namespace -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/templates/daemonset.yaml b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/daemonset.yaml
new file mode 100644
index 00000000..a742f24c
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/daemonset.yaml
@@ -0,0 +1,234 @@
+apiVersion: apps/v1
+kind: DaemonSet
+metadata:
+ name: {{ template "prometheus-node-exporter.fullname" . }}
+ namespace: {{ template "prometheus-node-exporter.namespace" . }}
+ labels: {{ include "prometheus-node-exporter.labels" . | indent 4 }}
+spec:
+ selector:
+ matchLabels:
+ {{- include "prometheus-node-exporter.selectorLabels" . | indent 6 }}
+ {{- if .Values.updateStrategy }}
+ updateStrategy:
+{{ toYaml .Values.updateStrategy | indent 4 }}
+ {{- end }}
+ template:
+ metadata:
+ labels: {{ include "prometheus-node-exporter.labels" . | indent 8 }}
+ {{- if .Values.podAnnotations }}
+ annotations:
+ {{- toYaml .Values.podAnnotations | nindent 8 }}
+ {{- end }}
+ spec:
+ automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
+ serviceAccountName: {{ template "prometheus-node-exporter.serviceAccountName" . }}
+{{- if .Values.securityContext }}
+ securityContext:
+{{ toYaml .Values.securityContext | indent 8 }}
+{{- end }}
+{{- if .Values.priorityClassName }}
+ priorityClassName: {{ .Values.priorityClassName }}
+{{- end }}
+ {{- if .Values.extraInitContainers }}
+ initContainers:
+ {{ toYaml .Values.extraInitContainers | nindent 6 }}
+ {{- end }}
+ containers:
+ - name: node-exporter
+ image: {{ include "prometheus-node-exporter.image" . }}
+ imagePullPolicy: {{ .Values.image.pullPolicy }}
+ args:
+ - --path.procfs=/host/proc
+ - --path.sysfs=/host/sys
+ {{- if .Values.hostRootFsMount.enabled }}
+ - --path.rootfs=/host/root
+ {{- end }}
+ - --web.listen-address=[$(HOST_IP)]:{{ .Values.service.port }}
+{{- if .Values.extraArgs }}
+{{ toYaml .Values.extraArgs | indent 12 }}
+{{- end }}
+ {{- with .Values.containerSecurityContext }}
+ securityContext: {{ toYaml . | nindent 12 }}
+ {{- end }}
+ env:
+ - name: HOST_IP
+ {{- if .Values.service.listenOnAllInterfaces }}
+ value: 0.0.0.0
+ {{- else }}
+ valueFrom:
+ fieldRef:
+ apiVersion: v1
+ fieldPath: status.hostIP
+ {{- end }}
+ {{- range $key, $value := .Values.env }}
+ - name: {{ $key }}
+ value: {{ $value | quote }}
+ {{- end }}
+ ports:
+ - name: {{ .Values.service.portName }}
+ containerPort: {{ .Values.service.port }}
+ protocol: TCP
+ livenessProbe:
+ failureThreshold: {{ .Values.livenessProbe.failureThreshold }}
+ httpGet:
+ httpHeaders:
+ {{- range $_, $header := .Values.livenessProbe.httpGet.httpHeaders }}
+ - name: {{ $header.name }}
+ value: {{ $header.value }}
+ {{- end }}
+ path: /
+ port: {{ .Values.service.port }}
+ scheme: {{ upper .Values.livenessProbe.httpGet.scheme }}
+ initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}
+ periodSeconds: {{ .Values.livenessProbe.periodSeconds }}
+ successThreshold: {{ .Values.livenessProbe.successThreshold }}
+ timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}
+ readinessProbe:
+ failureThreshold: {{ .Values.readinessProbe.failureThreshold }}
+ httpGet:
+ httpHeaders:
+ {{- range $_, $header := .Values.readinessProbe.httpGet.httpHeaders }}
+ - name: {{ $header.name }}
+ value: {{ $header.value }}
+ {{- end }}
+ path: /
+ port: {{ .Values.service.port }}
+ scheme: {{ upper .Values.readinessProbe.httpGet.scheme }}
+ initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
+ periodSeconds: {{ .Values.readinessProbe.periodSeconds }}
+ successThreshold: {{ .Values.readinessProbe.successThreshold }}
+ timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}
+ resources:
+{{ toYaml .Values.resources | indent 12 }}
+ volumeMounts:
+ - name: proc
+ mountPath: /host/proc
+ readOnly: true
+ - name: sys
+ mountPath: /host/sys
+ readOnly: true
+ {{- if .Values.hostRootFsMount.enabled }}
+ - name: root
+ mountPath: /host/root
+ {{- with .Values.hostRootFsMount.mountPropagation }}
+ mountPropagation: {{ . }}
+ {{- end }}
+ readOnly: true
+ {{- end }}
+ {{- if .Values.extraHostVolumeMounts }}
+ {{- range $_, $mount := .Values.extraHostVolumeMounts }}
+ - name: {{ $mount.name }}
+ mountPath: {{ $mount.mountPath }}
+ readOnly: {{ $mount.readOnly }}
+ {{- if $mount.mountPropagation }}
+ mountPropagation: {{ $mount.mountPropagation }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.sidecarVolumeMount }}
+ {{- range $_, $mount := .Values.sidecarVolumeMount }}
+ - name: {{ $mount.name }}
+ mountPath: {{ $mount.mountPath }}
+ readOnly: true
+ {{- end }}
+ {{- end }}
+ {{- if .Values.configmaps }}
+ {{- range $_, $mount := .Values.configmaps }}
+ - name: {{ $mount.name }}
+ mountPath: {{ $mount.mountPath }}
+ {{- end }}
+ {{- if .Values.secrets }}
+ {{- range $_, $mount := .Values.secrets }}
+ - name: {{ .name }}
+ mountPath: {{ .mountPath }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+{{- if .Values.sidecars }}
+{{ toYaml .Values.sidecars | indent 8 }}
+ {{- if or .Values.sidecarVolumeMount .Values.sidecarHostVolumeMounts }}
+ volumeMounts:
+ {{- range $_, $mount := .Values.sidecarVolumeMount }}
+ - name: {{ $mount.name }}
+ mountPath: {{ $mount.mountPath }}
+ readOnly: {{ $mount.readOnly }}
+ {{- end }}
+ {{- range $_, $mount := .Values.sidecarHostVolumeMounts }}
+ - name: {{ $mount.name }}
+ mountPath: {{ $mount.mountPath }}
+ readOnly: {{ $mount.readOnly }}
+ {{- if $mount.mountPropagation }}
+ mountPropagation: {{ $mount.mountPropagation }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+{{- end }}
+{{- if .Values.imagePullSecrets }}
+ imagePullSecrets:
+{{ toYaml .Values.imagePullSecrets | indent 8 }}
+ {{- end }}
+ hostNetwork: {{ .Values.hostNetwork }}
+ hostPID: {{ .Values.hostPID }}
+{{- if .Values.affinity }}
+ affinity:
+{{ toYaml .Values.affinity | indent 8 }}
+{{- end }}
+{{- with .Values.dnsConfig }}
+ dnsConfig:
+{{ toYaml . | indent 8 }}
+{{- end }}
+{{- if .Values.nodeSelector }}
+ nodeSelector:
+{{ toYaml .Values.nodeSelector | indent 8 }}
+{{- end }}
+ {{- with .Values.tolerations }}
+ tolerations:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ volumes:
+ - name: proc
+ hostPath:
+ path: /proc
+ - name: sys
+ hostPath:
+ path: /sys
+ {{- if .Values.hostRootFsMount.enabled }}
+ - name: root
+ hostPath:
+ path: /
+ {{- end }}
+ {{- if .Values.extraHostVolumeMounts }}
+ {{- range $_, $mount := .Values.extraHostVolumeMounts }}
+ - name: {{ $mount.name }}
+ hostPath:
+ path: {{ $mount.hostPath }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.sidecarVolumeMount }}
+ {{- range $_, $mount := .Values.sidecarVolumeMount }}
+ - name: {{ $mount.name }}
+ emptyDir:
+ medium: Memory
+ {{- end }}
+ {{- end }}
+ {{- if .Values.sidecarHostVolumeMounts }}
+ {{- range $_, $mount := .Values.sidecarHostVolumeMounts }}
+ - name: {{ $mount.name }}
+ hostPath:
+ path: {{ $mount.hostPath }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.configmaps }}
+ {{- range $_, $mount := .Values.configmaps }}
+ - name: {{ $mount.name }}
+ configMap:
+ name: {{ $mount.name }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.secrets }}
+ {{- range $_, $mount := .Values.secrets }}
+ - name: {{ $mount.name }}
+ secret:
+ secretName: {{ $mount.name }}
+ {{- end }}
+ {{- end }}
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/templates/endpoints.yaml b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/endpoints.yaml
new file mode 100644
index 00000000..ef3e270b
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/endpoints.yaml
@@ -0,0 +1,17 @@
+{{- if .Values.endpoints }}
+apiVersion: v1
+kind: Endpoints
+metadata:
+ name: {{ template "prometheus-node-exporter.fullname" . }}
+ namespace: {{ template "prometheus-node-exporter.namespace" . }}
+ labels: {{ include "prometheus-node-exporter.labels" . | indent 4 }}
+subsets:
+ - addresses:
+ {{- range .Values.endpoints }}
+ - ip: {{ . }}
+ {{- end }}
+ ports:
+ - name: {{ .Values.service.portName }}
+ port: 9100
+ protocol: TCP
+{{- end }}
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/templates/psp-clusterrole.yaml b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/psp-clusterrole.yaml
new file mode 100644
index 00000000..cb433369
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/psp-clusterrole.yaml
@@ -0,0 +1,15 @@
+{{- if .Values.rbac.create }}
+{{- if .Values.rbac.pspEnabled }}
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: psp-{{ template "prometheus-node-exporter.fullname" . }}
+ labels: {{ include "prometheus-node-exporter.labels" . | indent 4 }}
+rules:
+- apiGroups: ['extensions']
+ resources: ['podsecuritypolicies']
+ verbs: ['use']
+ resourceNames:
+ - {{ template "prometheus-node-exporter.fullname" . }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/templates/psp-clusterrolebinding.yaml b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/psp-clusterrolebinding.yaml
new file mode 100644
index 00000000..d36d93ec
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/psp-clusterrolebinding.yaml
@@ -0,0 +1,17 @@
+{{- if .Values.rbac.create }}
+{{- if .Values.rbac.pspEnabled }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: psp-{{ template "prometheus-node-exporter.fullname" . }}
+ labels: {{ include "prometheus-node-exporter.labels" . | indent 4 }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: psp-{{ template "prometheus-node-exporter.fullname" . }}
+subjects:
+ - kind: ServiceAccount
+ name: {{ template "prometheus-node-exporter.fullname" . }}
+ namespace: {{ template "prometheus-node-exporter.namespace" . }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/templates/psp.yaml b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/psp.yaml
new file mode 100644
index 00000000..ea8bcba3
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/psp.yaml
@@ -0,0 +1,50 @@
+{{- if .Values.rbac.create }}
+{{- if .Values.rbac.pspEnabled }}
+apiVersion: policy/v1beta1
+kind: PodSecurityPolicy
+metadata:
+ name: {{ template "prometheus-node-exporter.fullname" . }}
+ namespace: {{ template "prometheus-node-exporter.namespace" . }}
+ labels: {{ include "prometheus-node-exporter.labels" . | indent 4 }}
+{{- if .Values.rbac.pspAnnotations }}
+ annotations:
+{{ toYaml .Values.rbac.pspAnnotations | indent 4 }}
+{{- end}}
+spec:
+ privileged: false
+ # Allow core volume types.
+ volumes:
+ - 'configMap'
+ - 'emptyDir'
+ - 'projected'
+ - 'secret'
+ - 'downwardAPI'
+ - 'persistentVolumeClaim'
+ - 'hostPath'
+ hostNetwork: true
+ hostIPC: false
+ hostPID: true
+ hostPorts:
+ - min: 0
+ max: 65535
+ runAsUser:
+ # Permits the container to run with root privileges as well.
+ rule: 'RunAsAny'
+ seLinux:
+ # This policy assumes the nodes are using AppArmor rather than SELinux.
+ rule: 'RunAsAny'
+ supplementalGroups:
+ rule: 'MustRunAs'
+ ranges:
+ # Allow adding the root group.
+ - min: 0
+ max: 65535
+ fsGroup:
+ rule: 'MustRunAs'
+ ranges:
+ # Allow adding the root group.
+ - min: 0
+ max: 65535
+ readOnlyRootFilesystem: false
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/templates/service.yaml b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/service.yaml
new file mode 100644
index 00000000..fbed05ca
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/service.yaml
@@ -0,0 +1,22 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "prometheus-node-exporter.fullname" . }}
+ namespace: {{ template "prometheus-node-exporter.namespace" . }}
+ labels: {{ include "prometheus-node-exporter.labels" . | indent 4 }}
+{{- if .Values.service.annotations }}
+ annotations:
+{{ toYaml .Values.service.annotations | indent 4 }}
+{{- end }}
+spec:
+ type: {{ .Values.service.type }}
+ ports:
+ - port: {{ .Values.service.port }}
+ {{- if ( and (eq .Values.service.type "NodePort" ) (not (empty .Values.service.nodePort)) ) }}
+ nodePort: {{ .Values.service.nodePort }}
+ {{- end }}
+ targetPort: {{ .Values.service.targetPort }}
+ protocol: TCP
+ name: {{ .Values.service.portName }}
+ selector:
+ {{- include "prometheus-node-exporter.selectorLabels" . | indent 4 }}
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/templates/serviceaccount.yaml b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/serviceaccount.yaml
new file mode 100644
index 00000000..dc3fee6a
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/serviceaccount.yaml
@@ -0,0 +1,14 @@
+{{- if .Values.rbac.create -}}
+{{- if .Values.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ template "prometheus-node-exporter.serviceAccountName" . }}
+ namespace: {{ template "prometheus-node-exporter.namespace" . }}
+ labels: {{ include "prometheus-node-exporter.labels" . | indent 4 }}
+ annotations:
+{{ toYaml .Values.serviceAccount.annotations | indent 4 }}
+imagePullSecrets:
+{{ toYaml .Values.serviceAccount.imagePullSecrets | indent 2 }}
+{{- end -}}
+{{- end -}}
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/templates/servicemonitor.yaml b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/servicemonitor.yaml
new file mode 100644
index 00000000..3408c67d
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/templates/servicemonitor.yaml
@@ -0,0 +1,51 @@
+{{- if .Values.prometheus.monitor.enabled }}
+apiVersion: {{ .Values.prometheus.monitor.apiVersion | default "monitoring.coreos.com/v1" }}
+kind: ServiceMonitor
+metadata:
+ name: {{ template "prometheus-node-exporter.fullname" . }}
+ namespace: {{ template "prometheus-node-exporter.monitor-namespace" . }}
+ labels: {{ include "prometheus-node-exporter.labels" . | indent 4 }}
+ {{- if .Values.prometheus.monitor.additionalLabels }}
+ {{- toYaml .Values.prometheus.monitor.additionalLabels | nindent 4 }}
+ {{- end }}
+spec:
+ jobLabel: {{ default "app.kubernetes.io/name" .Values.prometheus.monitor.jobLabel }}
+ selector:
+ matchLabels:
+ {{- if .Values.prometheus.monitor.selectorOverride }}
+ {{ toYaml .Values.prometheus.monitor.selectorOverride | indent 6 }}
+ {{ else }}
+ {{ include "prometheus-node-exporter.selectorLabels" . | indent 6 }}
+ {{- end }}
+ endpoints:
+ - port: {{ .Values.service.portName }}
+ scheme: {{ .Values.prometheus.monitor.scheme }}
+ {{- with .Values.prometheus.monitor.basicAuth }}
+ basicAuth:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.prometheus.monitor.bearerTokenFile }}
+ bearerTokenFile: {{ . }}
+ {{- end }}
+ {{- with .Values.prometheus.monitor.tlsConfig }}
+ tlsConfig:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.prometheus.monitor.proxyUrl }}
+ proxyUrl: {{ . }}
+ {{- end }}
+ {{- with .Values.prometheus.monitor.interval }}
+ interval: {{ . }}
+ {{- end }}
+ {{- with .Values.prometheus.monitor.scrapeTimeout }}
+ scrapeTimeout: {{ . }}
+ {{- end }}
+ {{- with .Values.prometheus.monitor.relabelings }}
+ relabelings:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.prometheus.monitor.metricRelabelings }}
+ metricRelabelings:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/charts/prometheus-node-exporter/values.yaml b/kube-prometheus-stack/charts/prometheus-node-exporter/values.yaml
new file mode 100644
index 00000000..a00ae4d3
--- /dev/null
+++ b/kube-prometheus-stack/charts/prometheus-node-exporter/values.yaml
@@ -0,0 +1,248 @@
+# Default values for prometheus-node-exporter.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+image:
+ repository: quay.io/prometheus/node-exporter
+ # Overrides the image tag whose default is {{ printf "v%s" .Chart.AppVersion }}
+ tag: ""
+ pullPolicy: IfNotPresent
+ sha: ""
+
+imagePullSecrets: []
+# - name: "image-pull-secret"
+
+service:
+ type: ClusterIP
+ port: 9100
+ targetPort: 9100
+ nodePort:
+ portName: metrics
+ listenOnAllInterfaces: true
+ annotations:
+ prometheus.io/scrape: "true"
+
+# Additional environment variables that will be passed to the daemonset
+env: {}
+## env:
+## VARIABLE: value
+
+prometheus:
+ monitor:
+ enabled: false
+ additionalLabels: {}
+ namespace: ""
+
+ jobLabel: ""
+
+ scheme: http
+ basicAuth: {}
+ bearerTokenFile:
+ tlsConfig: {}
+
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+
+ ## Override serviceMonitor selector
+ ##
+ selectorOverride: {}
+
+ relabelings: []
+ metricRelabelings: []
+ interval: ""
+ scrapeTimeout: 10s
+ ## prometheus.monitor.apiVersion ApiVersion for the serviceMonitor Resource(defaults to "monitoring.coreos.com/v1")
+ apiVersion: ""
+
+## Customize the updateStrategy if set
+updateStrategy:
+ type: RollingUpdate
+ rollingUpdate:
+ maxUnavailable: 1
+
+resources: {}
+ # We usually recommend not to specify default resources and to leave this as a conscious
+ # choice for the user. This also increases chances charts run on environments with little
+ # resources, such as Minikube. If you do want to specify resources, uncomment the following
+ # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+ # limits:
+ # cpu: 200m
+ # memory: 50Mi
+ # requests:
+ # cpu: 100m
+ # memory: 30Mi
+
+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: {}
+ imagePullSecrets: []
+ automountServiceAccountToken: false
+
+securityContext:
+ fsGroup: 65534
+ runAsGroup: 65534
+ runAsNonRoot: true
+ runAsUser: 65534
+
+containerSecurityContext: {}
+ # capabilities:
+ # add:
+ # - SYS_TIME
+
+rbac:
+ ## If true, create & use RBAC resources
+ ##
+ create: true
+ ## If true, create & use Pod Security Policy resources
+ ## https://kubernetes.io/docs/concepts/policy/pod-security-policy/
+ pspEnabled: true
+ pspAnnotations: {}
+
+# for deployments that have node_exporter deployed outside of the cluster, list
+# their addresses here
+endpoints: []
+
+# Expose the service to the host network
+hostNetwork: true
+
+# Share the host process ID namespace
+hostPID: true
+
+# Mount the node's root file system (/) at /host/root in the container
+hostRootFsMount:
+ enabled: true
+ # Defines how new mounts in existing mounts on the node or in the container
+ # are propagated to the container or node, respectively. Possible values are
+ # None, HostToContainer, and Bidirectional. If this field is omitted, then
+ # None is used. More information on:
+ # https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation
+ mountPropagation: HostToContainer
+
+## Assign a group of affinity scheduling rules
+##
+affinity: {}
+# nodeAffinity:
+# requiredDuringSchedulingIgnoredDuringExecution:
+# nodeSelectorTerms:
+# - matchFields:
+# - key: metadata.name
+# operator: In
+# values:
+# - target-host-name
+
+# Annotations to be added to node exporter pods
+podAnnotations:
+ # Fix for very slow GKE cluster upgrades
+ cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
+
+# Extra labels to be added to node exporter pods
+podLabels: {}
+
+## set to true to add the release label so scraping of the servicemonitor with kube-prometheus-stack works out of the box
+releaseLabel: false
+
+# Custom DNS configuration to be added to prometheus-node-exporter pods
+dnsConfig: {}
+# nameservers:
+# - 1.2.3.4
+# searches:
+# - ns1.svc.cluster-domain.example
+# - my.dns.search.suffix
+# options:
+# - name: ndots
+# value: "2"
+# - name: edns0
+
+## Assign a nodeSelector if operating a hybrid cluster
+##
+nodeSelector: {}
+# beta.kubernetes.io/arch: amd64
+# beta.kubernetes.io/os: linux
+
+tolerations:
+ - effect: NoSchedule
+ operator: Exists
+
+## Assign a PriorityClassName to pods if set
+# priorityClassName: ""
+
+## Additional container arguments
+##
+extraArgs: []
+# - --collector.diskstats.ignored-devices=^(ram|loop|fd|(h|s|v)d[a-z]|nvme\\d+n\\d+p)\\d+$
+# - --collector.textfile.directory=/run/prometheus
+
+## Additional mounts from the host to node-exporter container
+##
+extraHostVolumeMounts: []
+# - name:
+# hostPath:
+# mountPath:
+# readOnly: true|false
+# mountPropagation: None|HostToContainer|Bidirectional
+
+## Additional configmaps to be mounted.
+##
+configmaps: []
+# - name:
+# mountPath:
+secrets: []
+# - name:
+# mountPath:
+## Override the deployment namespace
+##
+namespaceOverride: ""
+
+## Additional containers for export metrics to text file
+##
+sidecars: []
+## - name: nvidia-dcgm-exporter
+## image: nvidia/dcgm-exporter:1.4.3
+
+## Volume for sidecar containers
+##
+sidecarVolumeMount: []
+## - name: collector-textfiles
+## mountPath: /run/prometheus
+## readOnly: false
+
+## Additional mounts from the host to sidecar containers
+##
+sidecarHostVolumeMounts: []
+# - name:
+# hostPath:
+# mountPath:
+# readOnly: true|false
+# mountPropagation: None|HostToContainer|Bidirectional
+
+## Additional InitContainers to initialize the pod
+##
+extraInitContainers: []
+
+## Liveness probe
+##
+livenessProbe:
+ failureThreshold: 3
+ httpGet:
+ httpHeaders: []
+ scheme: http
+ initialDelaySeconds: 0
+ periodSeconds: 10
+ successThreshold: 1
+ timeoutSeconds: 1
+
+## Readiness probe
+##
+readinessProbe:
+ failureThreshold: 3
+ httpGet:
+ httpHeaders: []
+ scheme: http
+ initialDelaySeconds: 0
+ periodSeconds: 10
+ successThreshold: 1
+ timeoutSeconds: 1
diff --git a/kube-prometheus-stack/crds/crd-alertmanagerconfigs.yaml b/kube-prometheus-stack/crds/crd-alertmanagerconfigs.yaml
new file mode 100644
index 00000000..0d5f9ecb
--- /dev/null
+++ b/kube-prometheus-stack/crds/crd-alertmanagerconfigs.yaml
@@ -0,0 +1,4475 @@
+# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.2/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.9.2
+ creationTimestamp: null
+ name: alertmanagerconfigs.monitoring.coreos.com
+spec:
+ group: monitoring.coreos.com
+ names:
+ categories:
+ - prometheus-operator
+ kind: AlertmanagerConfig
+ listKind: AlertmanagerConfigList
+ plural: alertmanagerconfigs
+ shortNames:
+ - amcfg
+ singular: alertmanagerconfig
+ scope: Namespaced
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: AlertmanagerConfig defines a namespaced AlertmanagerConfig to
+ be aggregated across multiple namespaces configuring one Alertmanager cluster.
+ 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: AlertmanagerConfigSpec is a specification of the desired
+ behavior of the Alertmanager configuration. By definition, the Alertmanager
+ configuration only applies to alerts for which the `namespace` label
+ is equal to the namespace of the AlertmanagerConfig resource.
+ properties:
+ inhibitRules:
+ description: List of inhibition rules. The rules will only apply to
+ alerts matching the resource’s namespace.
+ items:
+ description: InhibitRule defines an inhibition rule that allows
+ to mute alerts when other alerts are already firing. See https://prometheus.io/docs/alerting/latest/configuration/#inhibit_rule
+ properties:
+ equal:
+ description: Labels that must have an equal value in the source
+ and target alert for the inhibition to take effect.
+ items:
+ type: string
+ type: array
+ sourceMatch:
+ description: Matchers for which one or more alerts have to exist
+ for the inhibition to take effect. The operator enforces that
+ the alert matches the resource’s namespace.
+ items:
+ description: Matcher defines how to match on alert's labels.
+ properties:
+ matchType:
+ description: Match operation available with AlertManager
+ >= v0.22.0 and takes precedence over Regex (deprecated)
+ if non-empty.
+ enum:
+ - '!='
+ - =
+ - =~
+ - '!~'
+ type: string
+ name:
+ description: Label to match.
+ minLength: 1
+ type: string
+ regex:
+ description: Whether to match on equality (false) or regular-expression
+ (true). Deprecated as of AlertManager >= v0.22.0 where
+ a user should use MatchType instead.
+ type: boolean
+ value:
+ description: Label value to match.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ targetMatch:
+ description: Matchers that have to be fulfilled in the alerts
+ to be muted. The operator enforces that the alert matches
+ the resource’s namespace.
+ items:
+ description: Matcher defines how to match on alert's labels.
+ properties:
+ matchType:
+ description: Match operation available with AlertManager
+ >= v0.22.0 and takes precedence over Regex (deprecated)
+ if non-empty.
+ enum:
+ - '!='
+ - =
+ - =~
+ - '!~'
+ type: string
+ name:
+ description: Label to match.
+ minLength: 1
+ type: string
+ regex:
+ description: Whether to match on equality (false) or regular-expression
+ (true). Deprecated as of AlertManager >= v0.22.0 where
+ a user should use MatchType instead.
+ type: boolean
+ value:
+ description: Label value to match.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ type: object
+ type: array
+ muteTimeIntervals:
+ description: List of MuteTimeInterval specifying when the routes should
+ be muted.
+ items:
+ description: MuteTimeInterval specifies the periods in time when
+ notifications will be muted
+ properties:
+ name:
+ description: Name of the time interval
+ type: string
+ timeIntervals:
+ description: TimeIntervals is a list of TimeInterval
+ items:
+ description: TimeInterval describes intervals of time
+ properties:
+ daysOfMonth:
+ description: DaysOfMonth is a list of DayOfMonthRange
+ items:
+ description: DayOfMonthRange is an inclusive range of
+ days of the month beginning at 1
+ properties:
+ end:
+ description: End of the inclusive range
+ maximum: 31
+ minimum: -31
+ type: integer
+ start:
+ description: Start of the inclusive range
+ maximum: 31
+ minimum: -31
+ type: integer
+ type: object
+ type: array
+ months:
+ description: Months is a list of MonthRange
+ items:
+ description: MonthRange is an inclusive range of months
+ of the year beginning in January Months can be specified
+ by name (e.g 'January') by numerical month (e.g '1')
+ or as an inclusive range (e.g 'January:March', '1:3',
+ '1:March')
+ pattern: ^((?i)january|february|march|april|may|june|july|august|september|october|november|december|[1-12])(?:((:((?i)january|february|march|april|may|june|july|august|september|october|november|december|[1-12]))$)|$)
+ type: string
+ type: array
+ times:
+ description: Times is a list of TimeRange
+ items:
+ description: TimeRange defines a start and end time
+ in 24hr format
+ properties:
+ endTime:
+ description: EndTime is the end time in 24hr format.
+ pattern: ^((([01][0-9])|(2[0-3])):[0-5][0-9])$|(^24:00$)
+ type: string
+ startTime:
+ description: StartTime is the start time in 24hr
+ format.
+ pattern: ^((([01][0-9])|(2[0-3])):[0-5][0-9])$|(^24:00$)
+ type: string
+ type: object
+ type: array
+ weekdays:
+ description: Weekdays is a list of WeekdayRange
+ items:
+ description: WeekdayRange is an inclusive range of days
+ of the week beginning on Sunday Days can be specified
+ by name (e.g 'Sunday') or as an inclusive range (e.g
+ 'Monday:Friday')
+ pattern: ^((?i)sun|mon|tues|wednes|thurs|fri|satur)day(?:((:(sun|mon|tues|wednes|thurs|fri|satur)day)$)|$)
+ type: string
+ type: array
+ years:
+ description: Years is a list of YearRange
+ items:
+ description: YearRange is an inclusive range of years
+ pattern: ^2\d{3}(?::2\d{3}|$)
+ type: string
+ type: array
+ type: object
+ type: array
+ type: object
+ type: array
+ receivers:
+ description: List of receivers.
+ items:
+ description: Receiver defines one or more notification integrations.
+ properties:
+ emailConfigs:
+ description: List of Email configurations.
+ items:
+ description: EmailConfig configures notifications via Email.
+ properties:
+ authIdentity:
+ description: The identity to use for authentication.
+ type: string
+ authPassword:
+ description: The secret's key that contains the password
+ to use for authentication. The secret needs to be in
+ the same namespace as the AlertmanagerConfig object
+ and accessible by the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ authSecret:
+ description: The secret's key that contains the CRAM-MD5
+ secret. The secret needs to be in the same namespace
+ as the AlertmanagerConfig object and accessible by the
+ Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ authUsername:
+ description: The username to use for authentication.
+ type: string
+ from:
+ description: The sender address.
+ type: string
+ headers:
+ description: Further headers email header key/value pairs.
+ Overrides any headers previously set by the notification
+ implementation.
+ items:
+ description: KeyValue defines a (key, value) tuple.
+ properties:
+ key:
+ description: Key of the tuple.
+ minLength: 1
+ type: string
+ value:
+ description: Value of the tuple.
+ type: string
+ required:
+ - key
+ - value
+ type: object
+ type: array
+ hello:
+ description: The hostname to identify to the SMTP server.
+ type: string
+ html:
+ description: The HTML body of the email notification.
+ type: string
+ requireTLS:
+ description: The SMTP TLS requirement. Note that Go does
+ not support unencrypted connections to remote SMTP endpoints.
+ type: boolean
+ sendResolved:
+ description: Whether or not to notify about resolved alerts.
+ type: boolean
+ smarthost:
+ description: The SMTP host and port through which emails
+ are sent. E.g. example.com:25
+ type: string
+ text:
+ description: The text body of the email notification.
+ type: string
+ tlsConfig:
+ description: TLS configuration
+ properties:
+ ca:
+ description: Struct containing the CA cert to use
+ for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for
+ the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert file
+ for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for
+ the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key file
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the targets.
+ type: string
+ type: object
+ to:
+ description: The email address to send notifications to.
+ type: string
+ type: object
+ type: array
+ name:
+ description: Name of the receiver. Must be unique across all
+ items from the list.
+ minLength: 1
+ type: string
+ opsgenieConfigs:
+ description: List of OpsGenie configurations.
+ items:
+ description: OpsGenieConfig configures notifications via OpsGenie.
+ See https://prometheus.io/docs/alerting/latest/configuration/#opsgenie_config
+ properties:
+ actions:
+ description: Comma separated list of actions that will
+ be available for the alert.
+ type: string
+ apiKey:
+ description: The secret's key that contains the OpsGenie
+ API key. The secret needs to be in the same namespace
+ as the AlertmanagerConfig object and accessible by the
+ Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ apiURL:
+ description: The URL to send OpsGenie API requests to.
+ type: string
+ description:
+ description: Description of the incident.
+ type: string
+ details:
+ description: A set of arbitrary key/value pairs that provide
+ further detail about the incident.
+ items:
+ description: KeyValue defines a (key, value) tuple.
+ properties:
+ key:
+ description: Key of the tuple.
+ minLength: 1
+ type: string
+ value:
+ description: Value of the tuple.
+ type: string
+ required:
+ - key
+ - value
+ type: object
+ type: array
+ entity:
+ description: Optional field that can be used to specify
+ which domain alert is related to.
+ type: string
+ httpConfig:
+ description: HTTP client configuration.
+ properties:
+ authorization:
+ description: Authorization header configuration for
+ the client. This is mutually exclusive with BasicAuth
+ and is only available starting from Alertmanager
+ v0.22+.
+ properties:
+ credentials:
+ description: The secret's key that contains the
+ credentials of the request
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults
+ to Bearer, Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth for the client. This is mutually
+ exclusive with Authorization. If both are defined,
+ BasicAuth takes precedence.
+ properties:
+ password:
+ description: The secret in the service monitor
+ namespace that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor
+ namespace that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenSecret:
+ description: The secret's key that contains the bearer
+ token to be used by the client for authentication.
+ The secret needs to be in the same namespace as
+ the AlertmanagerConfig object and accessible by
+ the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ followRedirects:
+ description: FollowRedirects specifies whether the
+ client should follow HTTP 3xx redirects.
+ type: boolean
+ oauth2:
+ description: OAuth2 client credentials used to fetch
+ a token for the targets.
+ properties:
+ clientId:
+ description: The secret or configmap containing
+ the OAuth2 client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2
+ client secret
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token
+ URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token
+ request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ proxyURL:
+ description: Optional proxy URL.
+ type: string
+ tlsConfig:
+ description: TLS configuration for the client.
+ properties:
+ ca:
+ description: Struct containing the CA cert to
+ use for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert
+ file for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key
+ file for the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the
+ targets.
+ type: string
+ type: object
+ type: object
+ message:
+ description: Alert text limited to 130 characters.
+ type: string
+ note:
+ description: Additional alert note.
+ type: string
+ priority:
+ description: Priority level of alert. Possible values
+ are P1, P2, P3, P4, and P5.
+ type: string
+ responders:
+ description: List of responders responsible for notifications.
+ items:
+ description: OpsGenieConfigResponder defines a responder
+ to an incident. One of `id`, `name` or `username`
+ has to be defined.
+ properties:
+ id:
+ description: ID of the responder.
+ type: string
+ name:
+ description: Name of the responder.
+ type: string
+ type:
+ description: Type of responder.
+ enum:
+ - team
+ - teams
+ - user
+ - escalation
+ - schedule
+ minLength: 1
+ type: string
+ username:
+ description: Username of the responder.
+ type: string
+ required:
+ - type
+ type: object
+ type: array
+ sendResolved:
+ description: Whether or not to notify about resolved alerts.
+ type: boolean
+ source:
+ description: Backlink to the sender of the notification.
+ type: string
+ tags:
+ description: Comma separated list of tags attached to
+ the notifications.
+ type: string
+ updateAlerts:
+ description: Whether to update message and description
+ of the alert in OpsGenie if it already exists By default,
+ the alert is never updated in OpsGenie, the new message
+ only appears in activity log.
+ type: boolean
+ type: object
+ type: array
+ pagerdutyConfigs:
+ description: List of PagerDuty configurations.
+ items:
+ description: PagerDutyConfig configures notifications via
+ PagerDuty. See https://prometheus.io/docs/alerting/latest/configuration/#pagerduty_config
+ properties:
+ class:
+ description: The class/type of the event.
+ type: string
+ client:
+ description: Client identification.
+ type: string
+ clientURL:
+ description: Backlink to the sender of notification.
+ type: string
+ component:
+ description: The part or component of the affected system
+ that is broken.
+ type: string
+ description:
+ description: Description of the incident.
+ type: string
+ details:
+ description: Arbitrary key/value pairs that provide further
+ detail about the incident.
+ items:
+ description: KeyValue defines a (key, value) tuple.
+ properties:
+ key:
+ description: Key of the tuple.
+ minLength: 1
+ type: string
+ value:
+ description: Value of the tuple.
+ type: string
+ required:
+ - key
+ - value
+ type: object
+ type: array
+ group:
+ description: A cluster or grouping of sources.
+ type: string
+ httpConfig:
+ description: HTTP client configuration.
+ properties:
+ authorization:
+ description: Authorization header configuration for
+ the client. This is mutually exclusive with BasicAuth
+ and is only available starting from Alertmanager
+ v0.22+.
+ properties:
+ credentials:
+ description: The secret's key that contains the
+ credentials of the request
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults
+ to Bearer, Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth for the client. This is mutually
+ exclusive with Authorization. If both are defined,
+ BasicAuth takes precedence.
+ properties:
+ password:
+ description: The secret in the service monitor
+ namespace that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor
+ namespace that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenSecret:
+ description: The secret's key that contains the bearer
+ token to be used by the client for authentication.
+ The secret needs to be in the same namespace as
+ the AlertmanagerConfig object and accessible by
+ the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ followRedirects:
+ description: FollowRedirects specifies whether the
+ client should follow HTTP 3xx redirects.
+ type: boolean
+ oauth2:
+ description: OAuth2 client credentials used to fetch
+ a token for the targets.
+ properties:
+ clientId:
+ description: The secret or configmap containing
+ the OAuth2 client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2
+ client secret
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token
+ URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token
+ request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ proxyURL:
+ description: Optional proxy URL.
+ type: string
+ tlsConfig:
+ description: TLS configuration for the client.
+ properties:
+ ca:
+ description: Struct containing the CA cert to
+ use for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert
+ file for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key
+ file for the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the
+ targets.
+ type: string
+ type: object
+ type: object
+ pagerDutyImageConfigs:
+ description: A list of image details to attach that provide
+ further detail about an incident.
+ items:
+ description: PagerDutyImageConfig attaches images to
+ an incident
+ properties:
+ alt:
+ description: Alt is the optional alternative text
+ for the image.
+ type: string
+ href:
+ description: Optional URL; makes the image a clickable
+ link.
+ type: string
+ src:
+ description: Src of the image being attached to
+ the incident
+ type: string
+ type: object
+ type: array
+ pagerDutyLinkConfigs:
+ description: A list of link details to attach that provide
+ further detail about an incident.
+ items:
+ description: PagerDutyLinkConfig attaches text links
+ to an incident
+ properties:
+ alt:
+ description: Text that describes the purpose of
+ the link, and can be used as the link's text.
+ type: string
+ href:
+ description: Href is the URL of the link to be attached
+ type: string
+ type: object
+ type: array
+ routingKey:
+ description: The secret's key that contains the PagerDuty
+ integration key (when using Events API v2). Either this
+ field or `serviceKey` needs to be defined. The secret
+ needs to be in the same namespace as the AlertmanagerConfig
+ object and accessible by the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ sendResolved:
+ description: Whether or not to notify about resolved alerts.
+ type: boolean
+ serviceKey:
+ description: The secret's key that contains the PagerDuty
+ service key (when using integration type "Prometheus").
+ Either this field or `routingKey` needs to be defined.
+ The secret needs to be in the same namespace as the
+ AlertmanagerConfig object and accessible by the Prometheus
+ Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ severity:
+ description: Severity of the incident.
+ type: string
+ url:
+ description: The URL to send requests to.
+ type: string
+ type: object
+ type: array
+ pushoverConfigs:
+ description: List of Pushover configurations.
+ items:
+ description: PushoverConfig configures notifications via Pushover.
+ See https://prometheus.io/docs/alerting/latest/configuration/#pushover_config
+ properties:
+ expire:
+ description: How long your notification will continue
+ to be retried for, unless the user acknowledges the
+ notification.
+ pattern: ^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$
+ type: string
+ html:
+ description: Whether notification message is HTML or plain
+ text.
+ type: boolean
+ httpConfig:
+ description: HTTP client configuration.
+ properties:
+ authorization:
+ description: Authorization header configuration for
+ the client. This is mutually exclusive with BasicAuth
+ and is only available starting from Alertmanager
+ v0.22+.
+ properties:
+ credentials:
+ description: The secret's key that contains the
+ credentials of the request
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults
+ to Bearer, Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth for the client. This is mutually
+ exclusive with Authorization. If both are defined,
+ BasicAuth takes precedence.
+ properties:
+ password:
+ description: The secret in the service monitor
+ namespace that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor
+ namespace that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenSecret:
+ description: The secret's key that contains the bearer
+ token to be used by the client for authentication.
+ The secret needs to be in the same namespace as
+ the AlertmanagerConfig object and accessible by
+ the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ followRedirects:
+ description: FollowRedirects specifies whether the
+ client should follow HTTP 3xx redirects.
+ type: boolean
+ oauth2:
+ description: OAuth2 client credentials used to fetch
+ a token for the targets.
+ properties:
+ clientId:
+ description: The secret or configmap containing
+ the OAuth2 client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2
+ client secret
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token
+ URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token
+ request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ proxyURL:
+ description: Optional proxy URL.
+ type: string
+ tlsConfig:
+ description: TLS configuration for the client.
+ properties:
+ ca:
+ description: Struct containing the CA cert to
+ use for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert
+ file for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key
+ file for the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the
+ targets.
+ type: string
+ type: object
+ type: object
+ message:
+ description: Notification message.
+ type: string
+ priority:
+ description: Priority, see https://pushover.net/api#priority
+ type: string
+ retry:
+ description: How often the Pushover servers will send
+ the same notification to the user. Must be at least
+ 30 seconds.
+ pattern: ^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$
+ type: string
+ sendResolved:
+ description: Whether or not to notify about resolved alerts.
+ type: boolean
+ sound:
+ description: The name of one of the sounds supported by
+ device clients to override the user's default sound
+ choice
+ type: string
+ title:
+ description: Notification title.
+ type: string
+ token:
+ description: The secret's key that contains the registered
+ application’s API token, see https://pushover.net/apps.
+ The secret needs to be in the same namespace as the
+ AlertmanagerConfig object and accessible by the Prometheus
+ Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ url:
+ description: A supplementary URL shown alongside the message.
+ type: string
+ urlTitle:
+ description: A title for supplementary URL, otherwise
+ just the URL is shown
+ type: string
+ userKey:
+ description: The secret's key that contains the recipient
+ user’s user key. The secret needs to be in the same
+ namespace as the AlertmanagerConfig object and accessible
+ by the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ type: object
+ type: array
+ slackConfigs:
+ description: List of Slack configurations.
+ items:
+ description: SlackConfig configures notifications via Slack.
+ See https://prometheus.io/docs/alerting/latest/configuration/#slack_config
+ properties:
+ actions:
+ description: A list of Slack actions that are sent with
+ each notification.
+ items:
+ description: SlackAction configures a single Slack action
+ that is sent with each notification. See https://api.slack.com/docs/message-attachments#action_fields
+ and https://api.slack.com/docs/message-buttons for
+ more information.
+ properties:
+ confirm:
+ description: SlackConfirmationField protect users
+ from destructive actions or particularly distinguished
+ decisions by asking them to confirm their button
+ click one more time. See https://api.slack.com/docs/interactive-message-field-guide#confirmation_fields
+ for more information.
+ properties:
+ dismissText:
+ type: string
+ okText:
+ type: string
+ text:
+ minLength: 1
+ type: string
+ title:
+ type: string
+ required:
+ - text
+ type: object
+ name:
+ type: string
+ style:
+ type: string
+ text:
+ minLength: 1
+ type: string
+ type:
+ minLength: 1
+ type: string
+ url:
+ type: string
+ value:
+ type: string
+ required:
+ - text
+ - type
+ type: object
+ type: array
+ apiURL:
+ description: The secret's key that contains the Slack
+ webhook URL. The secret needs to be in the same namespace
+ as the AlertmanagerConfig object and accessible by the
+ Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ callbackId:
+ type: string
+ channel:
+ description: The channel or user to send notifications
+ to.
+ type: string
+ color:
+ type: string
+ fallback:
+ type: string
+ fields:
+ description: A list of Slack fields that are sent with
+ each notification.
+ items:
+ description: SlackField configures a single Slack field
+ that is sent with each notification. Each field must
+ contain a title, value, and optionally, a boolean
+ value to indicate if the field is short enough to
+ be displayed next to other fields designated as short.
+ See https://api.slack.com/docs/message-attachments#fields
+ for more information.
+ properties:
+ short:
+ type: boolean
+ title:
+ minLength: 1
+ type: string
+ value:
+ minLength: 1
+ type: string
+ required:
+ - title
+ - value
+ type: object
+ type: array
+ footer:
+ type: string
+ httpConfig:
+ description: HTTP client configuration.
+ properties:
+ authorization:
+ description: Authorization header configuration for
+ the client. This is mutually exclusive with BasicAuth
+ and is only available starting from Alertmanager
+ v0.22+.
+ properties:
+ credentials:
+ description: The secret's key that contains the
+ credentials of the request
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults
+ to Bearer, Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth for the client. This is mutually
+ exclusive with Authorization. If both are defined,
+ BasicAuth takes precedence.
+ properties:
+ password:
+ description: The secret in the service monitor
+ namespace that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor
+ namespace that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenSecret:
+ description: The secret's key that contains the bearer
+ token to be used by the client for authentication.
+ The secret needs to be in the same namespace as
+ the AlertmanagerConfig object and accessible by
+ the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ followRedirects:
+ description: FollowRedirects specifies whether the
+ client should follow HTTP 3xx redirects.
+ type: boolean
+ oauth2:
+ description: OAuth2 client credentials used to fetch
+ a token for the targets.
+ properties:
+ clientId:
+ description: The secret or configmap containing
+ the OAuth2 client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2
+ client secret
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token
+ URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token
+ request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ proxyURL:
+ description: Optional proxy URL.
+ type: string
+ tlsConfig:
+ description: TLS configuration for the client.
+ properties:
+ ca:
+ description: Struct containing the CA cert to
+ use for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert
+ file for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key
+ file for the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the
+ targets.
+ type: string
+ type: object
+ type: object
+ iconEmoji:
+ type: string
+ iconURL:
+ type: string
+ imageURL:
+ type: string
+ linkNames:
+ type: boolean
+ mrkdwnIn:
+ items:
+ type: string
+ type: array
+ pretext:
+ type: string
+ sendResolved:
+ description: Whether or not to notify about resolved alerts.
+ type: boolean
+ shortFields:
+ type: boolean
+ text:
+ type: string
+ thumbURL:
+ type: string
+ title:
+ type: string
+ titleLink:
+ type: string
+ username:
+ type: string
+ type: object
+ type: array
+ snsConfigs:
+ description: List of SNS configurations
+ items:
+ description: SNSConfig configures notifications via AWS SNS.
+ See https://prometheus.io/docs/alerting/latest/configuration/#sns_configs
+ properties:
+ apiURL:
+ description: The SNS API URL i.e. https://sns.us-east-2.amazonaws.com.
+ If not specified, the SNS API URL from the SNS SDK will
+ be used.
+ type: string
+ attributes:
+ additionalProperties:
+ type: string
+ description: SNS message attributes.
+ type: object
+ httpConfig:
+ description: HTTP client configuration.
+ properties:
+ authorization:
+ description: Authorization header configuration for
+ the client. This is mutually exclusive with BasicAuth
+ and is only available starting from Alertmanager
+ v0.22+.
+ properties:
+ credentials:
+ description: The secret's key that contains the
+ credentials of the request
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults
+ to Bearer, Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth for the client. This is mutually
+ exclusive with Authorization. If both are defined,
+ BasicAuth takes precedence.
+ properties:
+ password:
+ description: The secret in the service monitor
+ namespace that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor
+ namespace that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenSecret:
+ description: The secret's key that contains the bearer
+ token to be used by the client for authentication.
+ The secret needs to be in the same namespace as
+ the AlertmanagerConfig object and accessible by
+ the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ followRedirects:
+ description: FollowRedirects specifies whether the
+ client should follow HTTP 3xx redirects.
+ type: boolean
+ oauth2:
+ description: OAuth2 client credentials used to fetch
+ a token for the targets.
+ properties:
+ clientId:
+ description: The secret or configmap containing
+ the OAuth2 client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2
+ client secret
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token
+ URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token
+ request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ proxyURL:
+ description: Optional proxy URL.
+ type: string
+ tlsConfig:
+ description: TLS configuration for the client.
+ properties:
+ ca:
+ description: Struct containing the CA cert to
+ use for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert
+ file for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key
+ file for the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the
+ targets.
+ type: string
+ type: object
+ type: object
+ message:
+ description: The message content of the SNS notification.
+ type: string
+ phoneNumber:
+ description: Phone number if message is delivered via
+ SMS in E.164 format. If you don't specify this value,
+ you must specify a value for the TopicARN or TargetARN.
+ type: string
+ sendResolved:
+ description: Whether or not to notify about resolved alerts.
+ type: boolean
+ sigv4:
+ description: Configures AWS's Signature Verification 4
+ signing process to sign requests.
+ properties:
+ accessKey:
+ description: AccessKey is the AWS API key. If blank,
+ the environment variable `AWS_ACCESS_KEY_ID` is
+ used.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ profile:
+ description: Profile is the named AWS profile used
+ to authenticate.
+ type: string
+ region:
+ description: Region is the AWS region. If blank, the
+ region from the default credentials chain used.
+ type: string
+ roleArn:
+ description: RoleArn is the named AWS profile used
+ to authenticate.
+ type: string
+ secretKey:
+ description: SecretKey is the AWS API secret. If blank,
+ the environment variable `AWS_SECRET_ACCESS_KEY`
+ is used.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ subject:
+ description: Subject line when the message is delivered
+ to email endpoints.
+ type: string
+ targetARN:
+ description: The mobile platform endpoint ARN if message
+ is delivered via mobile notifications. If you don't
+ specify this value, you must specify a value for the
+ topic_arn or PhoneNumber.
+ type: string
+ topicARN:
+ description: SNS topic ARN, i.e. arn:aws:sns:us-east-2:698519295917:My-Topic
+ If you don't specify this value, you must specify a
+ value for the PhoneNumber or TargetARN.
+ type: string
+ type: object
+ type: array
+ telegramConfigs:
+ description: List of Telegram configurations.
+ items:
+ description: TelegramConfig configures notifications via Telegram.
+ See https://prometheus.io/docs/alerting/latest/configuration/#telegram_config
+ properties:
+ apiURL:
+ description: The Telegram API URL i.e. https://api.telegram.org.
+ If not specified, default API URL will be used.
+ type: string
+ botToken:
+ description: Telegram bot token The secret needs to be
+ in the same namespace as the AlertmanagerConfig object
+ and accessible by the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ chatID:
+ description: The Telegram chat ID.
+ format: int64
+ type: integer
+ disableNotifications:
+ description: Disable telegram notifications
+ type: boolean
+ httpConfig:
+ description: HTTP client configuration.
+ properties:
+ authorization:
+ description: Authorization header configuration for
+ the client. This is mutually exclusive with BasicAuth
+ and is only available starting from Alertmanager
+ v0.22+.
+ properties:
+ credentials:
+ description: The secret's key that contains the
+ credentials of the request
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults
+ to Bearer, Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth for the client. This is mutually
+ exclusive with Authorization. If both are defined,
+ BasicAuth takes precedence.
+ properties:
+ password:
+ description: The secret in the service monitor
+ namespace that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor
+ namespace that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenSecret:
+ description: The secret's key that contains the bearer
+ token to be used by the client for authentication.
+ The secret needs to be in the same namespace as
+ the AlertmanagerConfig object and accessible by
+ the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ followRedirects:
+ description: FollowRedirects specifies whether the
+ client should follow HTTP 3xx redirects.
+ type: boolean
+ oauth2:
+ description: OAuth2 client credentials used to fetch
+ a token for the targets.
+ properties:
+ clientId:
+ description: The secret or configmap containing
+ the OAuth2 client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2
+ client secret
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token
+ URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token
+ request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ proxyURL:
+ description: Optional proxy URL.
+ type: string
+ tlsConfig:
+ description: TLS configuration for the client.
+ properties:
+ ca:
+ description: Struct containing the CA cert to
+ use for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert
+ file for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key
+ file for the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the
+ targets.
+ type: string
+ type: object
+ type: object
+ message:
+ description: Message template
+ type: string
+ parseMode:
+ description: Parse mode for telegram message
+ enum:
+ - MarkdownV2
+ - Markdown
+ - HTML
+ type: string
+ sendResolved:
+ description: Whether to notify about resolved alerts.
+ type: boolean
+ type: object
+ type: array
+ victoropsConfigs:
+ description: List of VictorOps configurations.
+ items:
+ description: VictorOpsConfig configures notifications via
+ VictorOps. See https://prometheus.io/docs/alerting/latest/configuration/#victorops_config
+ properties:
+ apiKey:
+ description: The secret's key that contains the API key
+ to use when talking to the VictorOps API. The secret
+ needs to be in the same namespace as the AlertmanagerConfig
+ object and accessible by the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ apiUrl:
+ description: The VictorOps API URL.
+ type: string
+ customFields:
+ description: Additional custom fields for notification.
+ items:
+ description: KeyValue defines a (key, value) tuple.
+ properties:
+ key:
+ description: Key of the tuple.
+ minLength: 1
+ type: string
+ value:
+ description: Value of the tuple.
+ type: string
+ required:
+ - key
+ - value
+ type: object
+ type: array
+ entityDisplayName:
+ description: Contains summary of the alerted problem.
+ type: string
+ httpConfig:
+ description: The HTTP client's configuration.
+ properties:
+ authorization:
+ description: Authorization header configuration for
+ the client. This is mutually exclusive with BasicAuth
+ and is only available starting from Alertmanager
+ v0.22+.
+ properties:
+ credentials:
+ description: The secret's key that contains the
+ credentials of the request
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults
+ to Bearer, Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth for the client. This is mutually
+ exclusive with Authorization. If both are defined,
+ BasicAuth takes precedence.
+ properties:
+ password:
+ description: The secret in the service monitor
+ namespace that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor
+ namespace that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenSecret:
+ description: The secret's key that contains the bearer
+ token to be used by the client for authentication.
+ The secret needs to be in the same namespace as
+ the AlertmanagerConfig object and accessible by
+ the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ followRedirects:
+ description: FollowRedirects specifies whether the
+ client should follow HTTP 3xx redirects.
+ type: boolean
+ oauth2:
+ description: OAuth2 client credentials used to fetch
+ a token for the targets.
+ properties:
+ clientId:
+ description: The secret or configmap containing
+ the OAuth2 client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2
+ client secret
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token
+ URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token
+ request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ proxyURL:
+ description: Optional proxy URL.
+ type: string
+ tlsConfig:
+ description: TLS configuration for the client.
+ properties:
+ ca:
+ description: Struct containing the CA cert to
+ use for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert
+ file for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key
+ file for the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the
+ targets.
+ type: string
+ type: object
+ type: object
+ messageType:
+ description: Describes the behavior of the alert (CRITICAL,
+ WARNING, INFO).
+ type: string
+ monitoringTool:
+ description: The monitoring tool the state message is
+ from.
+ type: string
+ routingKey:
+ description: A key used to map the alert to a team.
+ type: string
+ sendResolved:
+ description: Whether or not to notify about resolved alerts.
+ type: boolean
+ stateMessage:
+ description: Contains long explanation of the alerted
+ problem.
+ type: string
+ type: object
+ type: array
+ webhookConfigs:
+ description: List of webhook configurations.
+ items:
+ description: WebhookConfig configures notifications via a
+ generic receiver supporting the webhook payload. See https://prometheus.io/docs/alerting/latest/configuration/#webhook_config
+ properties:
+ httpConfig:
+ description: HTTP client configuration.
+ properties:
+ authorization:
+ description: Authorization header configuration for
+ the client. This is mutually exclusive with BasicAuth
+ and is only available starting from Alertmanager
+ v0.22+.
+ properties:
+ credentials:
+ description: The secret's key that contains the
+ credentials of the request
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults
+ to Bearer, Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth for the client. This is mutually
+ exclusive with Authorization. If both are defined,
+ BasicAuth takes precedence.
+ properties:
+ password:
+ description: The secret in the service monitor
+ namespace that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor
+ namespace that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenSecret:
+ description: The secret's key that contains the bearer
+ token to be used by the client for authentication.
+ The secret needs to be in the same namespace as
+ the AlertmanagerConfig object and accessible by
+ the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ followRedirects:
+ description: FollowRedirects specifies whether the
+ client should follow HTTP 3xx redirects.
+ type: boolean
+ oauth2:
+ description: OAuth2 client credentials used to fetch
+ a token for the targets.
+ properties:
+ clientId:
+ description: The secret or configmap containing
+ the OAuth2 client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2
+ client secret
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token
+ URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token
+ request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ proxyURL:
+ description: Optional proxy URL.
+ type: string
+ tlsConfig:
+ description: TLS configuration for the client.
+ properties:
+ ca:
+ description: Struct containing the CA cert to
+ use for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert
+ file for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key
+ file for the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the
+ targets.
+ type: string
+ type: object
+ type: object
+ maxAlerts:
+ description: Maximum number of alerts to be sent per webhook
+ message. When 0, all alerts are included.
+ format: int32
+ minimum: 0
+ type: integer
+ sendResolved:
+ description: Whether or not to notify about resolved alerts.
+ type: boolean
+ url:
+ description: The URL to send HTTP POST requests to. `urlSecret`
+ takes precedence over `url`. One of `urlSecret` and
+ `url` should be defined.
+ type: string
+ urlSecret:
+ description: The secret's key that contains the webhook
+ URL to send HTTP requests to. `urlSecret` takes precedence
+ over `url`. One of `urlSecret` and `url` should be defined.
+ The secret needs to be in the same namespace as the
+ AlertmanagerConfig object and accessible by the Prometheus
+ Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ type: object
+ type: array
+ wechatConfigs:
+ description: List of WeChat configurations.
+ items:
+ description: WeChatConfig configures notifications via WeChat.
+ See https://prometheus.io/docs/alerting/latest/configuration/#wechat_config
+ properties:
+ agentID:
+ type: string
+ apiSecret:
+ description: The secret's key that contains the WeChat
+ API key. The secret needs to be in the same namespace
+ as the AlertmanagerConfig object and accessible by the
+ Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ apiURL:
+ description: The WeChat API URL.
+ type: string
+ corpID:
+ description: The corp id for authentication.
+ type: string
+ httpConfig:
+ description: HTTP client configuration.
+ properties:
+ authorization:
+ description: Authorization header configuration for
+ the client. This is mutually exclusive with BasicAuth
+ and is only available starting from Alertmanager
+ v0.22+.
+ properties:
+ credentials:
+ description: The secret's key that contains the
+ credentials of the request
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults
+ to Bearer, Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth for the client. This is mutually
+ exclusive with Authorization. If both are defined,
+ BasicAuth takes precedence.
+ properties:
+ password:
+ description: The secret in the service monitor
+ namespace that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor
+ namespace that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenSecret:
+ description: The secret's key that contains the bearer
+ token to be used by the client for authentication.
+ The secret needs to be in the same namespace as
+ the AlertmanagerConfig object and accessible by
+ the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ followRedirects:
+ description: FollowRedirects specifies whether the
+ client should follow HTTP 3xx redirects.
+ type: boolean
+ oauth2:
+ description: OAuth2 client credentials used to fetch
+ a token for the targets.
+ properties:
+ clientId:
+ description: The secret or configmap containing
+ the OAuth2 client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2
+ client secret
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token
+ URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token
+ request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ proxyURL:
+ description: Optional proxy URL.
+ type: string
+ tlsConfig:
+ description: TLS configuration for the client.
+ properties:
+ ca:
+ description: Struct containing the CA cert to
+ use for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert
+ file for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to
+ use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to
+ select from. Must be a valid secret
+ key.
+ type: string
+ name:
+ description: 'Name of the referent. More
+ info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key
+ file for the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the
+ targets.
+ type: string
+ type: object
+ type: object
+ message:
+ description: API request data as defined by the WeChat
+ API.
+ type: string
+ messageType:
+ type: string
+ sendResolved:
+ description: Whether or not to notify about resolved alerts.
+ type: boolean
+ toParty:
+ type: string
+ toTag:
+ type: string
+ toUser:
+ type: string
+ type: object
+ type: array
+ required:
+ - name
+ type: object
+ type: array
+ route:
+ description: The Alertmanager route definition for alerts matching
+ the resource’s namespace. If present, it will be added to the generated
+ Alertmanager configuration as a first-level route.
+ properties:
+ continue:
+ description: Boolean indicating whether an alert should continue
+ matching subsequent sibling nodes. It will always be overridden
+ to true for the first-level route by the Prometheus operator.
+ type: boolean
+ groupBy:
+ description: List of labels to group by. Labels must not be repeated
+ (unique list). Special label "..." (aggregate by all possible
+ labels), if provided, must be the only element in the list.
+ items:
+ type: string
+ type: array
+ groupInterval:
+ description: 'How long to wait before sending an updated notification.
+ Must match the regular expression`^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$`
+ Example: "5m"'
+ type: string
+ groupWait:
+ description: 'How long to wait before sending the initial notification.
+ Must match the regular expression`^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$`
+ Example: "30s"'
+ type: string
+ matchers:
+ description: 'List of matchers that the alert’s labels should
+ match. For the first level route, the operator removes any existing
+ equality and regexp matcher on the `namespace` label and adds
+ a `namespace: ` matcher.'
+ items:
+ description: Matcher defines how to match on alert's labels.
+ properties:
+ matchType:
+ description: Match operation available with AlertManager
+ >= v0.22.0 and takes precedence over Regex (deprecated)
+ if non-empty.
+ enum:
+ - '!='
+ - =
+ - =~
+ - '!~'
+ type: string
+ name:
+ description: Label to match.
+ minLength: 1
+ type: string
+ regex:
+ description: Whether to match on equality (false) or regular-expression
+ (true). Deprecated as of AlertManager >= v0.22.0 where
+ a user should use MatchType instead.
+ type: boolean
+ value:
+ description: Label value to match.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ muteTimeIntervals:
+ description: 'Note: this comment applies to the field definition
+ above but appears below otherwise it gets included in the generated
+ manifest. CRD schema doesn''t support self-referential types
+ for now (see https://github.com/kubernetes/kubernetes/issues/62872).
+ We have to use an alternative type to circumvent the limitation.
+ The downside is that the Kube API can''t validate the data beyond
+ the fact that it is a valid JSON representation. MuteTimeIntervals
+ is a list of MuteTimeInterval names that will mute this route
+ when matched,'
+ items:
+ type: string
+ type: array
+ receiver:
+ description: Name of the receiver for this route. If not empty,
+ it should be listed in the `receivers` field.
+ type: string
+ repeatInterval:
+ description: 'How long to wait before repeating the last notification.
+ Must match the regular expression`^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$`
+ Example: "4h"'
+ type: string
+ routes:
+ description: Child routes.
+ items:
+ x-kubernetes-preserve-unknown-fields: true
+ type: array
+ type: object
+ type: object
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
diff --git a/kube-prometheus-stack/crds/crd-alertmanagers.yaml b/kube-prometheus-stack/crds/crd-alertmanagers.yaml
new file mode 100644
index 00000000..bc116307
--- /dev/null
+++ b/kube-prometheus-stack/crds/crd-alertmanagers.yaml
@@ -0,0 +1,6779 @@
+# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.2/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.9.2
+ creationTimestamp: null
+ name: alertmanagers.monitoring.coreos.com
+spec:
+ group: monitoring.coreos.com
+ names:
+ categories:
+ - prometheus-operator
+ kind: Alertmanager
+ listKind: AlertmanagerList
+ plural: alertmanagers
+ shortNames:
+ - am
+ singular: alertmanager
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - description: The version of Alertmanager
+ jsonPath: .spec.version
+ name: Version
+ type: string
+ - description: The desired replicas number of Alertmanagers
+ jsonPath: .spec.replicas
+ name: Replicas
+ type: integer
+ - jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1
+ schema:
+ openAPIV3Schema:
+ description: Alertmanager describes an Alertmanager cluster.
+ 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: 'Specification of the desired behavior of the Alertmanager
+ cluster. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status'
+ properties:
+ additionalPeers:
+ description: AdditionalPeers allows injecting a set of additional
+ Alertmanagers to peer with to form a highly available cluster.
+ items:
+ type: string
+ type: array
+ affinity:
+ description: If specified, the pod's scheduling constraints.
+ properties:
+ nodeAffinity:
+ description: Describes node affinity scheduling rules for the
+ pod.
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: The scheduler will prefer to schedule pods to
+ nodes that satisfy the affinity expressions specified by
+ this field, but it may choose a node that violates one or
+ more of the expressions. The node that is most preferred
+ is the one with the greatest sum of weights, i.e. for each
+ node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions,
+ etc.), compute a sum by iterating through the elements of
+ this field and adding "weight" to the sum if the node matches
+ the corresponding matchExpressions; the node(s) with the
+ highest sum are the most preferred.
+ items:
+ description: An empty preferred scheduling term matches
+ all objects with implicit weight 0 (i.e. it's a no-op).
+ A null preferred scheduling term matches no objects (i.e.
+ is also a no-op).
+ properties:
+ preference:
+ description: A node selector term, associated with the
+ corresponding weight.
+ properties:
+ matchExpressions:
+ description: A list of node selector requirements
+ by node's labels.
+ items:
+ description: A node selector requirement is a
+ selector that contains values, a key, and an
+ operator that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: Represents a key's relationship
+ to a set of values. Valid operators are
+ In, NotIn, Exists, DoesNotExist. Gt, and
+ Lt.
+ type: string
+ values:
+ description: 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. If the operator is Gt or
+ Lt, the values array must have a single
+ element, which will be interpreted as an
+ integer. This array is replaced during a
+ strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchFields:
+ description: A list of node selector requirements
+ by node's fields.
+ items:
+ description: A node selector requirement is a
+ selector that contains values, a key, and an
+ operator that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: Represents a key's relationship
+ to a set of values. Valid operators are
+ In, NotIn, Exists, DoesNotExist. Gt, and
+ Lt.
+ type: string
+ values:
+ description: 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. If the operator is Gt or
+ Lt, the values array must have a single
+ element, which will be interpreted as an
+ integer. This array is replaced during a
+ strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ type: object
+ x-kubernetes-map-type: atomic
+ weight:
+ description: Weight associated with matching the corresponding
+ nodeSelectorTerm, in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - preference
+ - weight
+ type: object
+ type: array
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: If the affinity requirements specified by this
+ field are not met at scheduling time, the pod will not be
+ scheduled onto the node. If the affinity requirements specified
+ by this field cease to be met at some point during pod execution
+ (e.g. due to an update), the system may or may not try to
+ eventually evict the pod from its node.
+ properties:
+ nodeSelectorTerms:
+ description: Required. A list of node selector terms.
+ The terms are ORed.
+ items:
+ description: A null or empty node selector term matches
+ no objects. The requirements of them are ANDed. The
+ TopologySelectorTerm type implements a subset of the
+ NodeSelectorTerm.
+ properties:
+ matchExpressions:
+ description: A list of node selector requirements
+ by node's labels.
+ items:
+ description: A node selector requirement is a
+ selector that contains values, a key, and an
+ operator that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: Represents a key's relationship
+ to a set of values. Valid operators are
+ In, NotIn, Exists, DoesNotExist. Gt, and
+ Lt.
+ type: string
+ values:
+ description: 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. If the operator is Gt or
+ Lt, the values array must have a single
+ element, which will be interpreted as an
+ integer. This array is replaced during a
+ strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchFields:
+ description: A list of node selector requirements
+ by node's fields.
+ items:
+ description: A node selector requirement is a
+ selector that contains values, a key, and an
+ operator that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: Represents a key's relationship
+ to a set of values. Valid operators are
+ In, NotIn, Exists, DoesNotExist. Gt, and
+ Lt.
+ type: string
+ values:
+ description: 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. If the operator is Gt or
+ Lt, the values array must have a single
+ element, which will be interpreted as an
+ integer. This array is replaced during a
+ strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ required:
+ - nodeSelectorTerms
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ podAffinity:
+ description: Describes pod affinity scheduling rules (e.g. co-locate
+ this pod in the same node, zone, etc. as some other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: The scheduler will prefer to schedule pods to
+ nodes that satisfy the affinity expressions specified by
+ this field, but it may choose a node that violates one or
+ more of the expressions. The node that is most preferred
+ is the one with the greatest sum of weights, i.e. for each
+ node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions,
+ etc.), compute a sum by iterating through the elements of
+ this field and adding "weight" to the sum if the node has
+ pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched WeightedPodAffinityTerm
+ fields are added per-node to find the most preferred node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term, associated
+ with the corresponding weight.
+ properties:
+ labelSelector:
+ description: A label query over a set of resources,
+ in this case pods.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaceSelector:
+ description: A label query over the set of namespaces
+ that the term applies to. The term is applied
+ to the union of the namespaces selected by this
+ field and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list
+ means "this pod's namespace". An empty selector
+ ({}) matches all namespaces.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: namespaces specifies a static list
+ of namespace names that the term applies to. The
+ term is applied to the union of the namespaces
+ listed in this field and the ones selected by
+ namespaceSelector. null or empty namespaces list
+ and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ topologyKey:
+ description: This pod should be co-located (affinity)
+ or not co-located (anti-affinity) with the pods
+ matching the labelSelector in the specified namespaces,
+ where co-located is defined as running on a node
+ whose value of the label with key topologyKey
+ matches that of any node on which any of the selected
+ pods is running. Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: weight associated with matching the corresponding
+ podAffinityTerm, in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: If the affinity requirements specified by this
+ field are not met at scheduling time, the pod will not be
+ scheduled onto the node. If the affinity requirements specified
+ by this field cease to be met at some point during pod execution
+ (e.g. due to a pod label update), the system may or may
+ not try to eventually evict the pod from its node. When
+ there are multiple elements, the lists of nodes corresponding
+ to each podAffinityTerm are intersected, i.e. all terms
+ must be satisfied.
+ items:
+ description: Defines a set of pods (namely those matching
+ the labelSelector relative to the given namespace(s))
+ that this pod should be co-located (affinity) or not co-located
+ (anti-affinity) with, where co-located is defined as running
+ on a node whose value of the label with key
+ matches that of any node on which a pod of the set of
+ pods is running
+ properties:
+ labelSelector:
+ description: A label query over a set of resources,
+ in this case pods.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaceSelector:
+ description: A label query over the set of namespaces
+ that the term applies to. The term is applied to the
+ union of the namespaces selected by this field and
+ the ones listed in the namespaces field. null selector
+ and null or empty namespaces list means "this pod's
+ namespace". An empty selector ({}) matches all namespaces.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: namespaces specifies a static list of namespace
+ names that the term applies to. The term is applied
+ to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector. null or
+ empty namespaces list and null namespaceSelector means
+ "this pod's namespace".
+ items:
+ type: string
+ type: array
+ topologyKey:
+ description: This pod should be co-located (affinity)
+ or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where
+ co-located is defined as running on a node whose value
+ of the label with key topologyKey matches that of
+ any node on which any of the selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ type: object
+ podAntiAffinity:
+ description: Describes pod anti-affinity scheduling rules (e.g.
+ avoid putting this pod in the same node, zone, etc. as some
+ other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: The scheduler will prefer to schedule pods to
+ nodes that satisfy the anti-affinity expressions specified
+ by this field, but it may choose a node that violates one
+ or more of the expressions. The node that is most preferred
+ is the one with the greatest sum of weights, i.e. for each
+ node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling anti-affinity expressions,
+ etc.), compute a sum by iterating through the elements of
+ this field and adding "weight" to the sum if the node has
+ pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched WeightedPodAffinityTerm
+ fields are added per-node to find the most preferred node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term, associated
+ with the corresponding weight.
+ properties:
+ labelSelector:
+ description: A label query over a set of resources,
+ in this case pods.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaceSelector:
+ description: A label query over the set of namespaces
+ that the term applies to. The term is applied
+ to the union of the namespaces selected by this
+ field and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list
+ means "this pod's namespace". An empty selector
+ ({}) matches all namespaces.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: namespaces specifies a static list
+ of namespace names that the term applies to. The
+ term is applied to the union of the namespaces
+ listed in this field and the ones selected by
+ namespaceSelector. null or empty namespaces list
+ and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ topologyKey:
+ description: This pod should be co-located (affinity)
+ or not co-located (anti-affinity) with the pods
+ matching the labelSelector in the specified namespaces,
+ where co-located is defined as running on a node
+ whose value of the label with key topologyKey
+ matches that of any node on which any of the selected
+ pods is running. Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: weight associated with matching the corresponding
+ podAffinityTerm, in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: If the anti-affinity requirements specified by
+ this field are not met at scheduling time, the pod will
+ not be scheduled onto the node. If the anti-affinity requirements
+ specified by this field cease to be met at some point during
+ pod execution (e.g. due to a pod label update), the system
+ may or may not try to eventually evict the pod from its
+ node. When there are multiple elements, the lists of nodes
+ corresponding to each podAffinityTerm are intersected, i.e.
+ all terms must be satisfied.
+ items:
+ description: Defines a set of pods (namely those matching
+ the labelSelector relative to the given namespace(s))
+ that this pod should be co-located (affinity) or not co-located
+ (anti-affinity) with, where co-located is defined as running
+ on a node whose value of the label with key
+ matches that of any node on which a pod of the set of
+ pods is running
+ properties:
+ labelSelector:
+ description: A label query over a set of resources,
+ in this case pods.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaceSelector:
+ description: A label query over the set of namespaces
+ that the term applies to. The term is applied to the
+ union of the namespaces selected by this field and
+ the ones listed in the namespaces field. null selector
+ and null or empty namespaces list means "this pod's
+ namespace". An empty selector ({}) matches all namespaces.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: namespaces specifies a static list of namespace
+ names that the term applies to. The term is applied
+ to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector. null or
+ empty namespaces list and null namespaceSelector means
+ "this pod's namespace".
+ items:
+ type: string
+ type: array
+ topologyKey:
+ description: This pod should be co-located (affinity)
+ or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where
+ co-located is defined as running on a node whose value
+ of the label with key topologyKey matches that of
+ any node on which any of the selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ type: object
+ type: object
+ alertmanagerConfigNamespaceSelector:
+ description: Namespaces to be selected for AlertmanagerConfig discovery.
+ If nil, only check own namespace.
+ 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
+ x-kubernetes-map-type: atomic
+ alertmanagerConfigSelector:
+ description: AlertmanagerConfigs to be selected for to merge and configure
+ Alertmanager with.
+ 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
+ x-kubernetes-map-type: atomic
+ alertmanagerConfiguration:
+ description: 'EXPERIMENTAL: alertmanagerConfiguration specifies the
+ configuration of Alertmanager. If defined, it takes precedence over
+ the `configSecret` field. This field may change in future releases.'
+ properties:
+ global:
+ description: Defines the global parameters of the Alertmanager
+ configuration.
+ properties:
+ httpConfig:
+ description: HTTP client configuration.
+ properties:
+ authorization:
+ description: Authorization header configuration for the
+ client. This is mutually exclusive with BasicAuth and
+ is only available starting from Alertmanager v0.22+.
+ properties:
+ credentials:
+ description: The secret's key that contains the credentials
+ of the request
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults
+ to Bearer, Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth for the client. This is mutually
+ exclusive with Authorization. If both are defined, BasicAuth
+ takes precedence.
+ properties:
+ password:
+ description: The secret in the service monitor namespace
+ that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor namespace
+ that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenSecret:
+ description: The secret's key that contains the bearer
+ token to be used by the client for authentication. The
+ secret needs to be in the same namespace as the Alertmanager
+ object and accessible by the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ followRedirects:
+ description: FollowRedirects specifies whether the client
+ should follow HTTP 3xx redirects.
+ type: boolean
+ oauth2:
+ description: OAuth2 client credentials used to fetch a
+ token for the targets.
+ properties:
+ clientId:
+ description: The secret or configmap containing the
+ OAuth2 client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for
+ the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2 client
+ secret
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ proxyURL:
+ description: Optional proxy URL.
+ type: string
+ tlsConfig:
+ description: TLS configuration for the client.
+ properties:
+ ca:
+ description: Struct containing the CA cert to use
+ for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for
+ the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert file
+ for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use
+ for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
+ or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for
+ the targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key file
+ for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the targets.
+ type: string
+ type: object
+ type: object
+ resolveTimeout:
+ description: ResolveTimeout is the default value used by alertmanager
+ if the alert does not include EndsAt, after this time passes
+ it can declare the alert as resolved if it has not been
+ updated. This has no impact on alerts from Prometheus, as
+ they always include EndsAt.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ type: object
+ name:
+ description: The name of the AlertmanagerConfig resource which
+ is used to generate the Alertmanager configuration. It must
+ be defined in the same namespace as the Alertmanager object.
+ The operator will not enforce a `namespace` label for routes
+ and inhibition rules.
+ minLength: 1
+ type: string
+ type: object
+ baseImage:
+ description: 'Base image that is used to deploy pods, without tag.
+ Deprecated: use ''image'' instead'
+ type: string
+ clusterAdvertiseAddress:
+ description: 'ClusterAdvertiseAddress is the explicit address to advertise
+ in cluster. Needs to be provided for non RFC1918 [1] (public) addresses.
+ [1] RFC1918: https://tools.ietf.org/html/rfc1918'
+ type: string
+ clusterGossipInterval:
+ description: Interval between gossip attempts.
+ pattern: ^(0|(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ clusterPeerTimeout:
+ description: Timeout for cluster peering.
+ pattern: ^(0|(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ clusterPushpullInterval:
+ description: Interval between pushpull attempts.
+ pattern: ^(0|(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ configMaps:
+ description: ConfigMaps is a list of ConfigMaps in the same namespace
+ as the Alertmanager object, which shall be mounted into the Alertmanager
+ Pods. The ConfigMaps are mounted into /etc/alertmanager/configmaps/.
+ items:
+ type: string
+ type: array
+ configSecret:
+ description: "ConfigSecret is the name of a Kubernetes Secret in the
+ same namespace as the Alertmanager object, which contains the configuration
+ for this Alertmanager instance. If empty, it defaults to 'alertmanager-'.
+ \n The Alertmanager configuration should be available under the
+ `alertmanager.yaml` key. Additional keys from the original secret
+ are copied to the generated secret. \n If either the secret or the
+ `alertmanager.yaml` key is missing, the operator provisions an Alertmanager
+ configuration with one empty receiver (effectively dropping alert
+ notifications)."
+ type: string
+ containers:
+ description: 'Containers allows injecting additional containers. This
+ is meant to allow adding an authentication proxy to an Alertmanager
+ pod. Containers described here modify an operator generated container
+ if they share the same name and modifications are done via a strategic
+ merge patch. The current container names are: `alertmanager` and
+ `config-reloader`. Overriding containers is entirely outside the
+ scope of what the maintainers will support and by doing so, you
+ accept that this behaviour may break at any time without notice.'
+ items:
+ description: A single application container that you want to run
+ within a pod.
+ properties:
+ args:
+ description: 'Arguments to the entrypoint. The container image''s
+ CMD is used if this is not provided. Variable references $(VAR_NAME)
+ are expanded using the container''s environment. If a variable
+ cannot be resolved, the reference in the input string will
+ be unchanged. Double $$ are reduced to a single $, which allows
+ for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
+ produce the string literal "$(VAR_NAME)". Escaped references
+ will never be expanded, regardless of whether the variable
+ exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
+ items:
+ type: string
+ type: array
+ command:
+ description: 'Entrypoint array. Not executed within a shell.
+ The container image''s ENTRYPOINT is used if this is not provided.
+ Variable references $(VAR_NAME) are expanded using the container''s
+ environment. If a variable cannot be resolved, the reference
+ in the input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME) syntax:
+ i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
+ Escaped references will never be expanded, regardless of whether
+ the variable exists or not. Cannot be updated. More info:
+ https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
+ items:
+ type: string
+ type: array
+ env:
+ description: List of environment variables to set in the container.
+ Cannot be updated.
+ items:
+ description: EnvVar represents an environment variable present
+ in a Container.
+ properties:
+ name:
+ description: Name of the environment variable. Must be
+ a C_IDENTIFIER.
+ type: string
+ value:
+ description: 'Variable references $(VAR_NAME) are expanded
+ using the previously defined environment variables in
+ the container and any service environment variables.
+ If a variable cannot be resolved, the reference in the
+ input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME)
+ syntax: i.e. "$$(VAR_NAME)" will produce the string
+ literal "$(VAR_NAME)". Escaped references will never
+ be expanded, regardless of whether the variable exists
+ or not. Defaults to "".'
+ type: string
+ valueFrom:
+ description: Source for the environment variable's value.
+ Cannot be used if value is not empty.
+ properties:
+ configMapKeyRef:
+ description: Selects a key of a ConfigMap.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ fieldRef:
+ description: 'Selects a field of the pod: supports
+ metadata.name, metadata.namespace, `metadata.labels['''']`,
+ `metadata.annotations['''']`, spec.nodeName,
+ spec.serviceAccountName, status.hostIP, status.podIP,
+ status.podIPs.'
+ properties:
+ apiVersion:
+ description: Version of the schema the FieldPath
+ is written in terms of, defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select in the
+ specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ resourceFieldRef:
+ description: 'Selects a resource of the container:
+ only resources limits and requests (limits.cpu,
+ limits.memory, limits.ephemeral-storage, requests.cpu,
+ requests.memory and requests.ephemeral-storage)
+ are currently supported.'
+ properties:
+ containerName:
+ description: 'Container name: required for volumes,
+ optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format of the
+ exposed resources, defaults to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ secretKeyRef:
+ description: Selects a key of a secret in the pod's
+ namespace
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ envFrom:
+ description: List of sources to populate environment variables
+ in the container. The keys defined within a source must be
+ a C_IDENTIFIER. All invalid keys will be reported as an event
+ when the container is starting. When a key exists in multiple
+ sources, the value associated with the last source will take
+ precedence. Values defined by an Env with a duplicate key
+ will take precedence. Cannot be updated.
+ items:
+ description: EnvFromSource represents the source of a set
+ of ConfigMaps
+ properties:
+ configMapRef:
+ description: The ConfigMap to select from
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap must be
+ defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ prefix:
+ description: An optional identifier to prepend to each
+ key in the ConfigMap. Must be a C_IDENTIFIER.
+ type: string
+ secretRef:
+ description: The Secret to select from
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ type: array
+ image:
+ description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images
+ This field is optional to allow higher level config management
+ to default or override container images in workload controllers
+ like Deployments and StatefulSets.'
+ type: string
+ imagePullPolicy:
+ description: 'Image pull policy. One of Always, Never, IfNotPresent.
+ Defaults to Always if :latest tag is specified, or IfNotPresent
+ otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images'
+ type: string
+ lifecycle:
+ description: Actions that the management system should take
+ in response to container lifecycle events. Cannot be updated.
+ properties:
+ postStart:
+ description: 'PostStart is called immediately after a container
+ is created. If the handler fails, the container is terminated
+ and restarted according to its restart policy. Other management
+ of the container blocks until the hook completes. More
+ info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for
+ the command is root ('/') in the container's
+ filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions
+ ('|', etc) won't work. To use a shell, you need
+ to explicitly call out to that shell. Exit status
+ of 0 is treated as live/healthy and non-zero is
+ unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to
+ the pod IP. You probably want to set "Host" in
+ httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the
+ host. Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ tcpSocket:
+ description: Deprecated. TCPSocket is NOT supported
+ as a LifecycleHandler and kept for the backward compatibility.
+ There are no validation of this field and lifecycle
+ hooks will fail in runtime when tcp handler is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ preStop:
+ description: 'PreStop is called immediately before a container
+ is terminated due to an API request or management event
+ such as liveness/startup probe failure, preemption, resource
+ contention, etc. The handler is not called if the container
+ crashes or exits. The Pod''s termination grace period
+ countdown begins before the PreStop hook is executed.
+ Regardless of the outcome of the handler, the container
+ will eventually terminate within the Pod''s termination
+ grace period (unless delayed by finalizers). Other management
+ of the container blocks until the hook completes or until
+ the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for
+ the command is root ('/') in the container's
+ filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions
+ ('|', etc) won't work. To use a shell, you need
+ to explicitly call out to that shell. Exit status
+ of 0 is treated as live/healthy and non-zero is
+ unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to
+ the pod IP. You probably want to set "Host" in
+ httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the
+ host. Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ tcpSocket:
+ description: Deprecated. TCPSocket is NOT supported
+ as a LifecycleHandler and kept for the backward compatibility.
+ There are no validation of this field and lifecycle
+ hooks will fail in runtime when tcp handler is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ type: object
+ livenessProbe:
+ description: 'Periodic probe of container liveness. Container
+ will be restarted if the probe fails. Cannot be updated. More
+ info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ name:
+ description: Name of the container specified as a DNS_LABEL.
+ Each container in a pod must have a unique name (DNS_LABEL).
+ Cannot be updated.
+ type: string
+ ports:
+ description: List of ports to expose from the container. Not
+ specifying a port here DOES NOT prevent that port from being
+ exposed. Any port which is listening on the default "0.0.0.0"
+ address inside a container will be accessible from the network.
+ Modifying this array with strategic merge patch may corrupt
+ the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255.
+ Cannot be updated.
+ items:
+ description: ContainerPort represents a network port in a
+ single container.
+ properties:
+ containerPort:
+ description: Number of port to expose on the pod's IP
+ address. This must be a valid port number, 0 < x < 65536.
+ format: int32
+ type: integer
+ hostIP:
+ description: What host IP to bind the external port to.
+ type: string
+ hostPort:
+ description: Number of port to expose on the host. If
+ specified, this must be a valid port number, 0 < x <
+ 65536. If HostNetwork is specified, this must match
+ ContainerPort. Most containers do not need this.
+ format: int32
+ type: integer
+ name:
+ description: If specified, this must be an IANA_SVC_NAME
+ and unique within the pod. Each named port in a pod
+ must have a unique name. Name for the port that can
+ be referred to by services.
+ type: string
+ protocol:
+ default: TCP
+ description: Protocol for port. Must be UDP, TCP, or SCTP.
+ Defaults to "TCP".
+ type: string
+ required:
+ - containerPort
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - containerPort
+ - protocol
+ x-kubernetes-list-type: map
+ readinessProbe:
+ description: 'Periodic probe of container service readiness.
+ Container will be removed from service endpoints if the probe
+ fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ resources:
+ description: 'Compute Resources required by this container.
+ Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount of compute
+ resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount of compute
+ resources required. If Requests is omitted for a container,
+ it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. More info:
+ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ securityContext:
+ description: 'SecurityContext defines the security options the
+ container should be run with. If set, the fields of SecurityContext
+ override the equivalent fields of PodSecurityContext. More
+ info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/'
+ properties:
+ allowPrivilegeEscalation:
+ description: 'AllowPrivilegeEscalation controls whether
+ a process can gain more privileges than its parent process.
+ This bool directly controls if the no_new_privs flag will
+ be set on the container process. AllowPrivilegeEscalation
+ is true always when the container is: 1) run as Privileged
+ 2) has CAP_SYS_ADMIN Note that this field cannot be set
+ when spec.os.name is windows.'
+ type: boolean
+ capabilities:
+ description: The capabilities to add/drop when running containers.
+ Defaults to the default set of capabilities granted by
+ the container runtime. Note that this field cannot be
+ set when spec.os.name is windows.
+ properties:
+ add:
+ description: Added capabilities
+ items:
+ description: Capability represent POSIX capabilities
+ type
+ type: string
+ type: array
+ drop:
+ description: Removed capabilities
+ items:
+ description: Capability represent POSIX capabilities
+ type
+ type: string
+ type: array
+ type: object
+ privileged:
+ description: Run container in privileged mode. Processes
+ in privileged containers are essentially equivalent to
+ root on the host. Defaults to false. Note that this field
+ cannot be set when spec.os.name is windows.
+ type: boolean
+ procMount:
+ description: procMount denotes the type of proc mount to
+ use for the containers. The default is DefaultProcMount
+ which uses the container runtime defaults for readonly
+ paths and masked paths. This requires the ProcMountType
+ feature flag to be enabled. Note that this field cannot
+ be set when spec.os.name is windows.
+ type: string
+ readOnlyRootFilesystem:
+ description: Whether this container has a read-only root
+ filesystem. Default is false. Note that this field cannot
+ be set when spec.os.name is windows.
+ type: boolean
+ runAsGroup:
+ description: The GID to run the entrypoint of the container
+ process. Uses runtime default if unset. May also be set
+ in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence. Note that this field cannot be set when
+ spec.os.name is windows.
+ format: int64
+ type: integer
+ runAsNonRoot:
+ description: Indicates that the container must run as a
+ non-root user. If true, the Kubelet will validate the
+ image at runtime to ensure that it does not run as UID
+ 0 (root) and fail to start the container if it does. If
+ unset or false, no such validation will be performed.
+ May also be set in PodSecurityContext. If set in both
+ SecurityContext and PodSecurityContext, the value specified
+ in SecurityContext takes precedence.
+ type: boolean
+ runAsUser:
+ description: The UID to run the entrypoint of the container
+ process. Defaults to user specified in image metadata
+ if unspecified. May also be set in PodSecurityContext. If
+ set in both SecurityContext and PodSecurityContext, the
+ value specified in SecurityContext takes precedence. Note
+ that this field cannot be set when spec.os.name is windows.
+ format: int64
+ type: integer
+ seLinuxOptions:
+ description: The SELinux context to be applied to the container.
+ If unspecified, the container runtime will allocate a
+ random SELinux context for each container. May also be
+ set in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence. Note that this field cannot be set when
+ spec.os.name is windows.
+ properties:
+ level:
+ description: Level is SELinux level label that applies
+ to the container.
+ type: string
+ role:
+ description: Role is a SELinux role label that applies
+ to the container.
+ type: string
+ type:
+ description: Type is a SELinux type label that applies
+ to the container.
+ type: string
+ user:
+ description: User is a SELinux user label that applies
+ to the container.
+ type: string
+ type: object
+ seccompProfile:
+ description: The seccomp options to use by this container.
+ If seccomp options are provided at both the pod & container
+ level, the container options override the pod options.
+ Note that this field cannot be set when spec.os.name is
+ windows.
+ properties:
+ localhostProfile:
+ description: localhostProfile indicates a profile defined
+ in a file on the node should be used. The profile
+ must be preconfigured on the node to work. Must be
+ a descending path, relative to the kubelet's configured
+ seccomp profile location. Must only be set if type
+ is "Localhost".
+ type: string
+ type:
+ description: "type indicates which kind of seccomp profile
+ will be applied. Valid options are: \n Localhost -
+ a profile defined in a file on the node should be
+ used. RuntimeDefault - the container runtime default
+ profile should be used. Unconfined - no profile should
+ be applied."
+ type: string
+ required:
+ - type
+ type: object
+ windowsOptions:
+ description: The Windows specific settings applied to all
+ containers. If unspecified, the options from the PodSecurityContext
+ will be used. If set in both SecurityContext and PodSecurityContext,
+ the value specified in SecurityContext takes precedence.
+ Note that this field cannot be set when spec.os.name is
+ linux.
+ properties:
+ gmsaCredentialSpec:
+ description: GMSACredentialSpec is where the GMSA admission
+ webhook (https://github.com/kubernetes-sigs/windows-gmsa)
+ inlines the contents of the GMSA credential spec named
+ by the GMSACredentialSpecName field.
+ type: string
+ gmsaCredentialSpecName:
+ description: GMSACredentialSpecName is the name of the
+ GMSA credential spec to use.
+ type: string
+ hostProcess:
+ description: HostProcess determines if a container should
+ be run as a 'Host Process' container. This field is
+ alpha-level and will only be honored by components
+ that enable the WindowsHostProcessContainers feature
+ flag. Setting this field without the feature flag
+ will result in errors when validating the Pod. All
+ of a Pod's containers must have the same effective
+ HostProcess value (it is not allowed to have a mix
+ of HostProcess containers and non-HostProcess containers). In
+ addition, if HostProcess is true then HostNetwork
+ must also be set to true.
+ type: boolean
+ runAsUserName:
+ description: The UserName in Windows to run the entrypoint
+ of the container process. Defaults to the user specified
+ in image metadata if unspecified. May also be set
+ in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence.
+ type: string
+ type: object
+ type: object
+ startupProbe:
+ description: 'StartupProbe indicates that the Pod has successfully
+ initialized. If specified, no other probes are executed until
+ this completes successfully. If this probe fails, the Pod
+ will be restarted, just as if the livenessProbe failed. This
+ can be used to provide different probe parameters at the beginning
+ of a Pod''s lifecycle, when it might take a long time to load
+ data or warm a cache, than during steady-state operation.
+ This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ stdin:
+ description: Whether this container should allocate a buffer
+ for stdin in the container runtime. If this is not set, reads
+ from stdin in the container will always result in EOF. Default
+ is false.
+ type: boolean
+ stdinOnce:
+ description: Whether the container runtime should close the
+ stdin channel after it has been opened by a single attach.
+ When stdin is true the stdin stream will remain open across
+ multiple attach sessions. If stdinOnce is set to true, stdin
+ is opened on container start, is empty until the first client
+ attaches to stdin, and then remains open and accepts data
+ until the client disconnects, at which time stdin is closed
+ and remains closed until the container is restarted. If this
+ flag is false, a container processes that reads from stdin
+ will never receive an EOF. Default is false
+ type: boolean
+ terminationMessagePath:
+ description: 'Optional: Path at which the file to which the
+ container''s termination message will be written is mounted
+ into the container''s filesystem. Message written is intended
+ to be brief final status, such as an assertion failure message.
+ Will be truncated by the node if greater than 4096 bytes.
+ The total message length across all containers will be limited
+ to 12kb. Defaults to /dev/termination-log. Cannot be updated.'
+ type: string
+ terminationMessagePolicy:
+ description: Indicate how the termination message should be
+ populated. File will use the contents of terminationMessagePath
+ to populate the container status message on both success and
+ failure. FallbackToLogsOnError will use the last chunk of
+ container log output if the termination message file is empty
+ and the container exited with an error. The log output is
+ limited to 2048 bytes or 80 lines, whichever is smaller. Defaults
+ to File. Cannot be updated.
+ type: string
+ tty:
+ description: Whether this container should allocate a TTY for
+ itself, also requires 'stdin' to be true. Default is false.
+ type: boolean
+ volumeDevices:
+ description: volumeDevices is the list of block devices to be
+ used by the container.
+ items:
+ description: volumeDevice describes a mapping of a raw block
+ device within a container.
+ properties:
+ devicePath:
+ description: devicePath is the path inside of the container
+ that the device will be mapped to.
+ type: string
+ name:
+ description: name must match the name of a persistentVolumeClaim
+ in the pod
+ type: string
+ required:
+ - devicePath
+ - name
+ type: object
+ type: array
+ volumeMounts:
+ description: Pod volumes to mount into the container's filesystem.
+ Cannot be updated.
+ items:
+ description: VolumeMount describes a mounting of a Volume
+ within a container.
+ properties:
+ mountPath:
+ description: Path within the container at which the volume
+ should be mounted. Must not contain ':'.
+ type: string
+ mountPropagation:
+ description: mountPropagation determines how mounts are
+ propagated from the host to container and the other
+ way around. When not set, MountPropagationNone is used.
+ This field is beta in 1.10.
+ type: string
+ name:
+ description: This must match the Name of a Volume.
+ type: string
+ readOnly:
+ description: Mounted read-only if true, read-write otherwise
+ (false or unspecified). Defaults to false.
+ type: boolean
+ subPath:
+ description: Path within the volume from which the container's
+ volume should be mounted. Defaults to "" (volume's root).
+ type: string
+ subPathExpr:
+ description: Expanded path within the volume from which
+ the container's volume should be mounted. Behaves similarly
+ to SubPath but environment variable references $(VAR_NAME)
+ are expanded using the container's environment. Defaults
+ to "" (volume's root). SubPathExpr and SubPath are mutually
+ exclusive.
+ type: string
+ required:
+ - mountPath
+ - name
+ type: object
+ type: array
+ workingDir:
+ description: Container's working directory. If not specified,
+ the container runtime's default will be used, which might
+ be configured in the container image. Cannot be updated.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ externalUrl:
+ description: The external URL the Alertmanager instances will be available
+ under. This is necessary to generate correct URLs. This is necessary
+ if Alertmanager is not served from root of a DNS name.
+ type: string
+ forceEnableClusterMode:
+ description: ForceEnableClusterMode ensures Alertmanager does not
+ deactivate the cluster mode when running with a single replica.
+ Use case is e.g. spanning an Alertmanager cluster across Kubernetes
+ clusters with a single replica in each.
+ type: boolean
+ hostAliases:
+ description: Pods' hostAliases configuration
+ items:
+ description: HostAlias holds the mapping between IP and hostnames
+ that will be injected as an entry in the pod's hosts file.
+ properties:
+ hostnames:
+ description: Hostnames for the above IP address.
+ items:
+ type: string
+ type: array
+ ip:
+ description: IP address of the host file entry.
+ type: string
+ required:
+ - hostnames
+ - ip
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - ip
+ x-kubernetes-list-type: map
+ image:
+ description: Image if specified has precedence over baseImage, tag
+ and sha combinations. Specifying the version is still necessary
+ to ensure the Prometheus Operator knows what version of Alertmanager
+ is being configured.
+ type: string
+ imagePullSecrets:
+ description: An optional list of references to secrets in the same
+ namespace to use for pulling prometheus and alertmanager images
+ from registries see http://kubernetes.io/docs/user-guide/images#specifying-imagepullsecrets-on-a-pod
+ items:
+ description: LocalObjectReference contains enough information to
+ let you locate the referenced object inside the same namespace.
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ initContainers:
+ description: 'InitContainers allows adding initContainers to the pod
+ definition. Those can be used to e.g. fetch secrets for injection
+ into the Alertmanager configuration from external sources. Any errors
+ during the execution of an initContainer will lead to a restart
+ of the Pod. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
+ Using initContainers for any use case other then secret fetching
+ is entirely outside the scope of what the maintainers will support
+ and by doing so, you accept that this behaviour may break at any
+ time without notice.'
+ items:
+ description: A single application container that you want to run
+ within a pod.
+ properties:
+ args:
+ description: 'Arguments to the entrypoint. The container image''s
+ CMD is used if this is not provided. Variable references $(VAR_NAME)
+ are expanded using the container''s environment. If a variable
+ cannot be resolved, the reference in the input string will
+ be unchanged. Double $$ are reduced to a single $, which allows
+ for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
+ produce the string literal "$(VAR_NAME)". Escaped references
+ will never be expanded, regardless of whether the variable
+ exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
+ items:
+ type: string
+ type: array
+ command:
+ description: 'Entrypoint array. Not executed within a shell.
+ The container image''s ENTRYPOINT is used if this is not provided.
+ Variable references $(VAR_NAME) are expanded using the container''s
+ environment. If a variable cannot be resolved, the reference
+ in the input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME) syntax:
+ i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
+ Escaped references will never be expanded, regardless of whether
+ the variable exists or not. Cannot be updated. More info:
+ https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
+ items:
+ type: string
+ type: array
+ env:
+ description: List of environment variables to set in the container.
+ Cannot be updated.
+ items:
+ description: EnvVar represents an environment variable present
+ in a Container.
+ properties:
+ name:
+ description: Name of the environment variable. Must be
+ a C_IDENTIFIER.
+ type: string
+ value:
+ description: 'Variable references $(VAR_NAME) are expanded
+ using the previously defined environment variables in
+ the container and any service environment variables.
+ If a variable cannot be resolved, the reference in the
+ input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME)
+ syntax: i.e. "$$(VAR_NAME)" will produce the string
+ literal "$(VAR_NAME)". Escaped references will never
+ be expanded, regardless of whether the variable exists
+ or not. Defaults to "".'
+ type: string
+ valueFrom:
+ description: Source for the environment variable's value.
+ Cannot be used if value is not empty.
+ properties:
+ configMapKeyRef:
+ description: Selects a key of a ConfigMap.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ fieldRef:
+ description: 'Selects a field of the pod: supports
+ metadata.name, metadata.namespace, `metadata.labels['''']`,
+ `metadata.annotations['''']`, spec.nodeName,
+ spec.serviceAccountName, status.hostIP, status.podIP,
+ status.podIPs.'
+ properties:
+ apiVersion:
+ description: Version of the schema the FieldPath
+ is written in terms of, defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select in the
+ specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ resourceFieldRef:
+ description: 'Selects a resource of the container:
+ only resources limits and requests (limits.cpu,
+ limits.memory, limits.ephemeral-storage, requests.cpu,
+ requests.memory and requests.ephemeral-storage)
+ are currently supported.'
+ properties:
+ containerName:
+ description: 'Container name: required for volumes,
+ optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format of the
+ exposed resources, defaults to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ secretKeyRef:
+ description: Selects a key of a secret in the pod's
+ namespace
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ envFrom:
+ description: List of sources to populate environment variables
+ in the container. The keys defined within a source must be
+ a C_IDENTIFIER. All invalid keys will be reported as an event
+ when the container is starting. When a key exists in multiple
+ sources, the value associated with the last source will take
+ precedence. Values defined by an Env with a duplicate key
+ will take precedence. Cannot be updated.
+ items:
+ description: EnvFromSource represents the source of a set
+ of ConfigMaps
+ properties:
+ configMapRef:
+ description: The ConfigMap to select from
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap must be
+ defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ prefix:
+ description: An optional identifier to prepend to each
+ key in the ConfigMap. Must be a C_IDENTIFIER.
+ type: string
+ secretRef:
+ description: The Secret to select from
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ type: array
+ image:
+ description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images
+ This field is optional to allow higher level config management
+ to default or override container images in workload controllers
+ like Deployments and StatefulSets.'
+ type: string
+ imagePullPolicy:
+ description: 'Image pull policy. One of Always, Never, IfNotPresent.
+ Defaults to Always if :latest tag is specified, or IfNotPresent
+ otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images'
+ type: string
+ lifecycle:
+ description: Actions that the management system should take
+ in response to container lifecycle events. Cannot be updated.
+ properties:
+ postStart:
+ description: 'PostStart is called immediately after a container
+ is created. If the handler fails, the container is terminated
+ and restarted according to its restart policy. Other management
+ of the container blocks until the hook completes. More
+ info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for
+ the command is root ('/') in the container's
+ filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions
+ ('|', etc) won't work. To use a shell, you need
+ to explicitly call out to that shell. Exit status
+ of 0 is treated as live/healthy and non-zero is
+ unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to
+ the pod IP. You probably want to set "Host" in
+ httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the
+ host. Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ tcpSocket:
+ description: Deprecated. TCPSocket is NOT supported
+ as a LifecycleHandler and kept for the backward compatibility.
+ There are no validation of this field and lifecycle
+ hooks will fail in runtime when tcp handler is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ preStop:
+ description: 'PreStop is called immediately before a container
+ is terminated due to an API request or management event
+ such as liveness/startup probe failure, preemption, resource
+ contention, etc. The handler is not called if the container
+ crashes or exits. The Pod''s termination grace period
+ countdown begins before the PreStop hook is executed.
+ Regardless of the outcome of the handler, the container
+ will eventually terminate within the Pod''s termination
+ grace period (unless delayed by finalizers). Other management
+ of the container blocks until the hook completes or until
+ the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for
+ the command is root ('/') in the container's
+ filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions
+ ('|', etc) won't work. To use a shell, you need
+ to explicitly call out to that shell. Exit status
+ of 0 is treated as live/healthy and non-zero is
+ unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to
+ the pod IP. You probably want to set "Host" in
+ httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the
+ host. Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ tcpSocket:
+ description: Deprecated. TCPSocket is NOT supported
+ as a LifecycleHandler and kept for the backward compatibility.
+ There are no validation of this field and lifecycle
+ hooks will fail in runtime when tcp handler is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ type: object
+ livenessProbe:
+ description: 'Periodic probe of container liveness. Container
+ will be restarted if the probe fails. Cannot be updated. More
+ info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ name:
+ description: Name of the container specified as a DNS_LABEL.
+ Each container in a pod must have a unique name (DNS_LABEL).
+ Cannot be updated.
+ type: string
+ ports:
+ description: List of ports to expose from the container. Not
+ specifying a port here DOES NOT prevent that port from being
+ exposed. Any port which is listening on the default "0.0.0.0"
+ address inside a container will be accessible from the network.
+ Modifying this array with strategic merge patch may corrupt
+ the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255.
+ Cannot be updated.
+ items:
+ description: ContainerPort represents a network port in a
+ single container.
+ properties:
+ containerPort:
+ description: Number of port to expose on the pod's IP
+ address. This must be a valid port number, 0 < x < 65536.
+ format: int32
+ type: integer
+ hostIP:
+ description: What host IP to bind the external port to.
+ type: string
+ hostPort:
+ description: Number of port to expose on the host. If
+ specified, this must be a valid port number, 0 < x <
+ 65536. If HostNetwork is specified, this must match
+ ContainerPort. Most containers do not need this.
+ format: int32
+ type: integer
+ name:
+ description: If specified, this must be an IANA_SVC_NAME
+ and unique within the pod. Each named port in a pod
+ must have a unique name. Name for the port that can
+ be referred to by services.
+ type: string
+ protocol:
+ default: TCP
+ description: Protocol for port. Must be UDP, TCP, or SCTP.
+ Defaults to "TCP".
+ type: string
+ required:
+ - containerPort
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - containerPort
+ - protocol
+ x-kubernetes-list-type: map
+ readinessProbe:
+ description: 'Periodic probe of container service readiness.
+ Container will be removed from service endpoints if the probe
+ fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ resources:
+ description: 'Compute Resources required by this container.
+ Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount of compute
+ resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount of compute
+ resources required. If Requests is omitted for a container,
+ it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. More info:
+ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ securityContext:
+ description: 'SecurityContext defines the security options the
+ container should be run with. If set, the fields of SecurityContext
+ override the equivalent fields of PodSecurityContext. More
+ info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/'
+ properties:
+ allowPrivilegeEscalation:
+ description: 'AllowPrivilegeEscalation controls whether
+ a process can gain more privileges than its parent process.
+ This bool directly controls if the no_new_privs flag will
+ be set on the container process. AllowPrivilegeEscalation
+ is true always when the container is: 1) run as Privileged
+ 2) has CAP_SYS_ADMIN Note that this field cannot be set
+ when spec.os.name is windows.'
+ type: boolean
+ capabilities:
+ description: The capabilities to add/drop when running containers.
+ Defaults to the default set of capabilities granted by
+ the container runtime. Note that this field cannot be
+ set when spec.os.name is windows.
+ properties:
+ add:
+ description: Added capabilities
+ items:
+ description: Capability represent POSIX capabilities
+ type
+ type: string
+ type: array
+ drop:
+ description: Removed capabilities
+ items:
+ description: Capability represent POSIX capabilities
+ type
+ type: string
+ type: array
+ type: object
+ privileged:
+ description: Run container in privileged mode. Processes
+ in privileged containers are essentially equivalent to
+ root on the host. Defaults to false. Note that this field
+ cannot be set when spec.os.name is windows.
+ type: boolean
+ procMount:
+ description: procMount denotes the type of proc mount to
+ use for the containers. The default is DefaultProcMount
+ which uses the container runtime defaults for readonly
+ paths and masked paths. This requires the ProcMountType
+ feature flag to be enabled. Note that this field cannot
+ be set when spec.os.name is windows.
+ type: string
+ readOnlyRootFilesystem:
+ description: Whether this container has a read-only root
+ filesystem. Default is false. Note that this field cannot
+ be set when spec.os.name is windows.
+ type: boolean
+ runAsGroup:
+ description: The GID to run the entrypoint of the container
+ process. Uses runtime default if unset. May also be set
+ in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence. Note that this field cannot be set when
+ spec.os.name is windows.
+ format: int64
+ type: integer
+ runAsNonRoot:
+ description: Indicates that the container must run as a
+ non-root user. If true, the Kubelet will validate the
+ image at runtime to ensure that it does not run as UID
+ 0 (root) and fail to start the container if it does. If
+ unset or false, no such validation will be performed.
+ May also be set in PodSecurityContext. If set in both
+ SecurityContext and PodSecurityContext, the value specified
+ in SecurityContext takes precedence.
+ type: boolean
+ runAsUser:
+ description: The UID to run the entrypoint of the container
+ process. Defaults to user specified in image metadata
+ if unspecified. May also be set in PodSecurityContext. If
+ set in both SecurityContext and PodSecurityContext, the
+ value specified in SecurityContext takes precedence. Note
+ that this field cannot be set when spec.os.name is windows.
+ format: int64
+ type: integer
+ seLinuxOptions:
+ description: The SELinux context to be applied to the container.
+ If unspecified, the container runtime will allocate a
+ random SELinux context for each container. May also be
+ set in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence. Note that this field cannot be set when
+ spec.os.name is windows.
+ properties:
+ level:
+ description: Level is SELinux level label that applies
+ to the container.
+ type: string
+ role:
+ description: Role is a SELinux role label that applies
+ to the container.
+ type: string
+ type:
+ description: Type is a SELinux type label that applies
+ to the container.
+ type: string
+ user:
+ description: User is a SELinux user label that applies
+ to the container.
+ type: string
+ type: object
+ seccompProfile:
+ description: The seccomp options to use by this container.
+ If seccomp options are provided at both the pod & container
+ level, the container options override the pod options.
+ Note that this field cannot be set when spec.os.name is
+ windows.
+ properties:
+ localhostProfile:
+ description: localhostProfile indicates a profile defined
+ in a file on the node should be used. The profile
+ must be preconfigured on the node to work. Must be
+ a descending path, relative to the kubelet's configured
+ seccomp profile location. Must only be set if type
+ is "Localhost".
+ type: string
+ type:
+ description: "type indicates which kind of seccomp profile
+ will be applied. Valid options are: \n Localhost -
+ a profile defined in a file on the node should be
+ used. RuntimeDefault - the container runtime default
+ profile should be used. Unconfined - no profile should
+ be applied."
+ type: string
+ required:
+ - type
+ type: object
+ windowsOptions:
+ description: The Windows specific settings applied to all
+ containers. If unspecified, the options from the PodSecurityContext
+ will be used. If set in both SecurityContext and PodSecurityContext,
+ the value specified in SecurityContext takes precedence.
+ Note that this field cannot be set when spec.os.name is
+ linux.
+ properties:
+ gmsaCredentialSpec:
+ description: GMSACredentialSpec is where the GMSA admission
+ webhook (https://github.com/kubernetes-sigs/windows-gmsa)
+ inlines the contents of the GMSA credential spec named
+ by the GMSACredentialSpecName field.
+ type: string
+ gmsaCredentialSpecName:
+ description: GMSACredentialSpecName is the name of the
+ GMSA credential spec to use.
+ type: string
+ hostProcess:
+ description: HostProcess determines if a container should
+ be run as a 'Host Process' container. This field is
+ alpha-level and will only be honored by components
+ that enable the WindowsHostProcessContainers feature
+ flag. Setting this field without the feature flag
+ will result in errors when validating the Pod. All
+ of a Pod's containers must have the same effective
+ HostProcess value (it is not allowed to have a mix
+ of HostProcess containers and non-HostProcess containers). In
+ addition, if HostProcess is true then HostNetwork
+ must also be set to true.
+ type: boolean
+ runAsUserName:
+ description: The UserName in Windows to run the entrypoint
+ of the container process. Defaults to the user specified
+ in image metadata if unspecified. May also be set
+ in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence.
+ type: string
+ type: object
+ type: object
+ startupProbe:
+ description: 'StartupProbe indicates that the Pod has successfully
+ initialized. If specified, no other probes are executed until
+ this completes successfully. If this probe fails, the Pod
+ will be restarted, just as if the livenessProbe failed. This
+ can be used to provide different probe parameters at the beginning
+ of a Pod''s lifecycle, when it might take a long time to load
+ data or warm a cache, than during steady-state operation.
+ This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ stdin:
+ description: Whether this container should allocate a buffer
+ for stdin in the container runtime. If this is not set, reads
+ from stdin in the container will always result in EOF. Default
+ is false.
+ type: boolean
+ stdinOnce:
+ description: Whether the container runtime should close the
+ stdin channel after it has been opened by a single attach.
+ When stdin is true the stdin stream will remain open across
+ multiple attach sessions. If stdinOnce is set to true, stdin
+ is opened on container start, is empty until the first client
+ attaches to stdin, and then remains open and accepts data
+ until the client disconnects, at which time stdin is closed
+ and remains closed until the container is restarted. If this
+ flag is false, a container processes that reads from stdin
+ will never receive an EOF. Default is false
+ type: boolean
+ terminationMessagePath:
+ description: 'Optional: Path at which the file to which the
+ container''s termination message will be written is mounted
+ into the container''s filesystem. Message written is intended
+ to be brief final status, such as an assertion failure message.
+ Will be truncated by the node if greater than 4096 bytes.
+ The total message length across all containers will be limited
+ to 12kb. Defaults to /dev/termination-log. Cannot be updated.'
+ type: string
+ terminationMessagePolicy:
+ description: Indicate how the termination message should be
+ populated. File will use the contents of terminationMessagePath
+ to populate the container status message on both success and
+ failure. FallbackToLogsOnError will use the last chunk of
+ container log output if the termination message file is empty
+ and the container exited with an error. The log output is
+ limited to 2048 bytes or 80 lines, whichever is smaller. Defaults
+ to File. Cannot be updated.
+ type: string
+ tty:
+ description: Whether this container should allocate a TTY for
+ itself, also requires 'stdin' to be true. Default is false.
+ type: boolean
+ volumeDevices:
+ description: volumeDevices is the list of block devices to be
+ used by the container.
+ items:
+ description: volumeDevice describes a mapping of a raw block
+ device within a container.
+ properties:
+ devicePath:
+ description: devicePath is the path inside of the container
+ that the device will be mapped to.
+ type: string
+ name:
+ description: name must match the name of a persistentVolumeClaim
+ in the pod
+ type: string
+ required:
+ - devicePath
+ - name
+ type: object
+ type: array
+ volumeMounts:
+ description: Pod volumes to mount into the container's filesystem.
+ Cannot be updated.
+ items:
+ description: VolumeMount describes a mounting of a Volume
+ within a container.
+ properties:
+ mountPath:
+ description: Path within the container at which the volume
+ should be mounted. Must not contain ':'.
+ type: string
+ mountPropagation:
+ description: mountPropagation determines how mounts are
+ propagated from the host to container and the other
+ way around. When not set, MountPropagationNone is used.
+ This field is beta in 1.10.
+ type: string
+ name:
+ description: This must match the Name of a Volume.
+ type: string
+ readOnly:
+ description: Mounted read-only if true, read-write otherwise
+ (false or unspecified). Defaults to false.
+ type: boolean
+ subPath:
+ description: Path within the volume from which the container's
+ volume should be mounted. Defaults to "" (volume's root).
+ type: string
+ subPathExpr:
+ description: Expanded path within the volume from which
+ the container's volume should be mounted. Behaves similarly
+ to SubPath but environment variable references $(VAR_NAME)
+ are expanded using the container's environment. Defaults
+ to "" (volume's root). SubPathExpr and SubPath are mutually
+ exclusive.
+ type: string
+ required:
+ - mountPath
+ - name
+ type: object
+ type: array
+ workingDir:
+ description: Container's working directory. If not specified,
+ the container runtime's default will be used, which might
+ be configured in the container image. Cannot be updated.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ listenLocal:
+ description: ListenLocal makes the Alertmanager server listen on loopback,
+ so that it does not bind against the Pod IP. Note this is only for
+ the Alertmanager UI, not the gossip communication.
+ type: boolean
+ logFormat:
+ description: Log format for Alertmanager to be configured with.
+ enum:
+ - ""
+ - logfmt
+ - json
+ type: string
+ logLevel:
+ description: Log level for Alertmanager to be configured with.
+ enum:
+ - ""
+ - debug
+ - info
+ - warn
+ - error
+ type: string
+ minReadySeconds:
+ description: Minimum number of seconds for which a newly created pod
+ should be ready without any of its container crashing for it to
+ be considered available. Defaults to 0 (pod will be considered available
+ as soon as it is ready) This is an alpha field and requires enabling
+ StatefulSetMinReadySeconds feature gate.
+ format: int32
+ type: integer
+ nodeSelector:
+ additionalProperties:
+ type: string
+ description: Define which Nodes the Pods are scheduled on.
+ type: object
+ paused:
+ description: If set to true all actions on the underlying managed
+ objects are not goint to be performed, except for delete actions.
+ type: boolean
+ podMetadata:
+ description: PodMetadata configures Labels and Annotations which are
+ propagated to the alertmanager pods.
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: 'Annotations is an unstructured key value map stored
+ with a resource that may be set by external tools to store and
+ retrieve arbitrary metadata. They are not queryable and should
+ be preserved when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations'
+ type: object
+ labels:
+ additionalProperties:
+ type: string
+ description: 'Map of string keys and values that can be used to
+ organize and categorize (scope and select) objects. May match
+ selectors of replication controllers and services. More info:
+ http://kubernetes.io/docs/user-guide/labels'
+ type: object
+ name:
+ description: 'Name must be unique within a namespace. Is required
+ when creating resources, although some resources may allow a
+ client to request the generation of an appropriate name automatically.
+ Name is primarily intended for creation idempotence and configuration
+ definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names'
+ type: string
+ type: object
+ portName:
+ description: Port name used for the pods and governing service. This
+ defaults to web
+ type: string
+ priorityClassName:
+ description: Priority class assigned to the Pods
+ type: string
+ replicas:
+ description: Size is the expected size of the alertmanager cluster.
+ The controller will eventually make the size of the running cluster
+ equal to the expected size.
+ format: int32
+ type: integer
+ resources:
+ description: Define resources requests and limits for single Pods.
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount of compute resources
+ allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount of compute
+ resources required. If Requests is omitted for a container,
+ it defaults to Limits if that is explicitly specified, otherwise
+ to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ retention:
+ default: 120h
+ description: Time duration Alertmanager shall retain data for. Default
+ is '120h', and must match the regular expression `[0-9]+(ms|s|m|h)`
+ (milliseconds seconds minutes hours).
+ pattern: ^(0|(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ routePrefix:
+ description: The route prefix Alertmanager registers HTTP handlers
+ for. This is useful, if using ExternalURL and a proxy is rewriting
+ HTTP routes of a request, and the actual ExternalURL is still true,
+ but the server serves requests under a different route prefix. For
+ example for use with `kubectl proxy`.
+ type: string
+ secrets:
+ description: Secrets is a list of Secrets in the same namespace as
+ the Alertmanager object, which shall be mounted into the Alertmanager
+ Pods. The Secrets are mounted into /etc/alertmanager/secrets/.
+ items:
+ type: string
+ type: array
+ securityContext:
+ description: SecurityContext holds pod-level security attributes and
+ common container settings. This defaults to the default PodSecurityContext.
+ properties:
+ fsGroup:
+ description: "A special supplemental group that applies to all
+ containers in a pod. Some volume types allow the Kubelet to
+ change the ownership of that volume to be owned by the pod:
+ \n 1. The owning GID will be the FSGroup 2. The setgid bit is
+ set (new files created in the volume will be owned by FSGroup)
+ 3. The permission bits are OR'd with rw-rw---- \n If unset,
+ the Kubelet will not modify the ownership and permissions of
+ any volume. Note that this field cannot be set when spec.os.name
+ is windows."
+ format: int64
+ type: integer
+ fsGroupChangePolicy:
+ description: 'fsGroupChangePolicy defines behavior of changing
+ ownership and permission of the volume before being exposed
+ inside Pod. This field will only apply to volume types which
+ support fsGroup based ownership(and permissions). It will have
+ no effect on ephemeral volume types such as: secret, configmaps
+ and emptydir. Valid values are "OnRootMismatch" and "Always".
+ If not specified, "Always" is used. Note that this field cannot
+ be set when spec.os.name is windows.'
+ type: string
+ runAsGroup:
+ description: The GID to run the entrypoint of the container process.
+ Uses runtime default if unset. May also be set in SecurityContext. If
+ set in both SecurityContext and PodSecurityContext, the value
+ specified in SecurityContext takes precedence for that container.
+ Note that this field cannot be set when spec.os.name is windows.
+ format: int64
+ type: integer
+ runAsNonRoot:
+ description: Indicates that the container must run as a non-root
+ user. If true, the Kubelet will validate the image at runtime
+ to ensure that it does not run as UID 0 (root) and fail to start
+ the container if it does. If unset or false, no such validation
+ will be performed. May also be set in SecurityContext. If set
+ in both SecurityContext and PodSecurityContext, the value specified
+ in SecurityContext takes precedence.
+ type: boolean
+ runAsUser:
+ description: The UID to run the entrypoint of the container process.
+ Defaults to user specified in image metadata if unspecified.
+ May also be set in SecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence for that container. Note that this field cannot
+ be set when spec.os.name is windows.
+ format: int64
+ type: integer
+ seLinuxOptions:
+ description: The SELinux context to be applied to all containers.
+ If unspecified, the container runtime will allocate a random
+ SELinux context for each container. May also be set in SecurityContext. If
+ set in both SecurityContext and PodSecurityContext, the value
+ specified in SecurityContext takes precedence for that container.
+ Note that this field cannot be set when spec.os.name is windows.
+ properties:
+ level:
+ description: Level is SELinux level label that applies to
+ the container.
+ type: string
+ role:
+ description: Role is a SELinux role label that applies to
+ the container.
+ type: string
+ type:
+ description: Type is a SELinux type label that applies to
+ the container.
+ type: string
+ user:
+ description: User is a SELinux user label that applies to
+ the container.
+ type: string
+ type: object
+ seccompProfile:
+ description: The seccomp options to use by the containers in this
+ pod. Note that this field cannot be set when spec.os.name is
+ windows.
+ properties:
+ localhostProfile:
+ description: localhostProfile indicates a profile defined
+ in a file on the node should be used. The profile must be
+ preconfigured on the node to work. Must be a descending
+ path, relative to the kubelet's configured seccomp profile
+ location. Must only be set if type is "Localhost".
+ type: string
+ type:
+ description: "type indicates which kind of seccomp profile
+ will be applied. Valid options are: \n Localhost - a profile
+ defined in a file on the node should be used. RuntimeDefault
+ - the container runtime default profile should be used.
+ Unconfined - no profile should be applied."
+ type: string
+ required:
+ - type
+ type: object
+ supplementalGroups:
+ description: A list of groups applied to the first process run
+ in each container, in addition to the container's primary GID. If
+ unspecified, no groups will be added to any container. Note
+ that this field cannot be set when spec.os.name is windows.
+ items:
+ format: int64
+ type: integer
+ type: array
+ sysctls:
+ description: Sysctls hold a list of namespaced sysctls used for
+ the pod. Pods with unsupported sysctls (by the container runtime)
+ might fail to launch. Note that this field cannot be set when
+ spec.os.name is windows.
+ items:
+ description: Sysctl defines a kernel parameter to be set
+ properties:
+ name:
+ description: Name of a property to set
+ type: string
+ value:
+ description: Value of a property to set
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ windowsOptions:
+ description: The Windows specific settings applied to all containers.
+ If unspecified, the options within a container's SecurityContext
+ will be used. If set in both SecurityContext and PodSecurityContext,
+ the value specified in SecurityContext takes precedence. Note
+ that this field cannot be set when spec.os.name is linux.
+ properties:
+ gmsaCredentialSpec:
+ description: GMSACredentialSpec is where the GMSA admission
+ webhook (https://github.com/kubernetes-sigs/windows-gmsa)
+ inlines the contents of the GMSA credential spec named by
+ the GMSACredentialSpecName field.
+ type: string
+ gmsaCredentialSpecName:
+ description: GMSACredentialSpecName is the name of the GMSA
+ credential spec to use.
+ type: string
+ hostProcess:
+ description: HostProcess determines if a container should
+ be run as a 'Host Process' container. This field is alpha-level
+ and will only be honored by components that enable the WindowsHostProcessContainers
+ feature flag. Setting this field without the feature flag
+ will result in errors when validating the Pod. All of a
+ Pod's containers must have the same effective HostProcess
+ value (it is not allowed to have a mix of HostProcess containers
+ and non-HostProcess containers). In addition, if HostProcess
+ is true then HostNetwork must also be set to true.
+ type: boolean
+ runAsUserName:
+ description: The UserName in Windows to run the entrypoint
+ of the container process. Defaults to the user specified
+ in image metadata if unspecified. May also be set in PodSecurityContext.
+ If set in both SecurityContext and PodSecurityContext, the
+ value specified in SecurityContext takes precedence.
+ type: string
+ type: object
+ type: object
+ serviceAccountName:
+ description: ServiceAccountName is the name of the ServiceAccount
+ to use to run the Prometheus Pods.
+ type: string
+ sha:
+ description: 'SHA of Alertmanager container image to be deployed.
+ Defaults to the value of `version`. Similar to a tag, but the SHA
+ explicitly deploys an immutable container image. Version and Tag
+ are ignored if SHA is set. Deprecated: use ''image'' instead. The
+ image digest can be specified as part of the image URL.'
+ type: string
+ storage:
+ description: Storage is the definition of how storage will be used
+ by the Alertmanager instances.
+ properties:
+ disableMountSubPath:
+ description: 'Deprecated: subPath usage will be disabled by default
+ in a future release, this option will become unnecessary. DisableMountSubPath
+ allows to remove any subPath usage in volume mounts.'
+ type: boolean
+ emptyDir:
+ description: 'EmptyDirVolumeSource to be used by the Prometheus
+ StatefulSets. If specified, used in place of any volumeClaimTemplate.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir'
+ properties:
+ medium:
+ description: 'medium represents what type of storage medium
+ should back this directory. The default is "" which means
+ to use the node''s default medium. Must be an empty string
+ (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir'
+ type: string
+ sizeLimit:
+ anyOf:
+ - type: integer
+ - type: string
+ description: 'sizeLimit is the total amount of local storage
+ required for this EmptyDir volume. The size limit is also
+ applicable for memory medium. The maximum usage on memory
+ medium EmptyDir would be the minimum value between the SizeLimit
+ specified here and the sum of memory limits of all containers
+ in a pod. The default is nil which means that the limit
+ is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir'
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type: object
+ ephemeral:
+ description: 'EphemeralVolumeSource to be used by the Prometheus
+ StatefulSets. This is a beta field in k8s 1.21, for lower versions,
+ starting with k8s 1.19, it requires enabling the GenericEphemeralVolume
+ feature gate. More info: https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/#generic-ephemeral-volumes'
+ properties:
+ volumeClaimTemplate:
+ description: "Will be used to create a stand-alone PVC to
+ provision the volume. The pod in which this EphemeralVolumeSource
+ is embedded will be the owner of the PVC, i.e. the PVC will
+ be deleted together with the pod. The name of the PVC will
+ be `-` where `` is the
+ name from the `PodSpec.Volumes` array entry. Pod validation
+ will reject the pod if the concatenated name is not valid
+ for a PVC (for example, too long). \n An existing PVC with
+ that name that is not owned by the pod will *not* be used
+ for the pod to avoid using an unrelated volume by mistake.
+ Starting the pod is then blocked until the unrelated PVC
+ is removed. If such a pre-created PVC is meant to be used
+ by the pod, the PVC has to updated with an owner reference
+ to the pod once the pod exists. Normally this should not
+ be necessary, but it may be useful when manually reconstructing
+ a broken cluster. \n This field is read-only and no changes
+ will be made by Kubernetes to the PVC after it has been
+ created. \n Required, must not be nil."
+ properties:
+ metadata:
+ description: May contain labels and annotations that will
+ be copied into the PVC when creating it. No other fields
+ are allowed and will be rejected during validation.
+ type: object
+ spec:
+ description: The specification for the PersistentVolumeClaim.
+ The entire content is copied unchanged into the PVC
+ that gets created from this template. The same fields
+ as in a PersistentVolumeClaim are also valid here.
+ properties:
+ accessModes:
+ description: 'accessModes contains the desired access
+ modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+ items:
+ type: string
+ type: array
+ dataSource:
+ description: 'dataSource field can be used to specify
+ either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
+ * An existing PVC (PersistentVolumeClaim) If the
+ provisioner or an external controller can support
+ the specified data source, it will create a new
+ volume based on the contents of the specified data
+ source. If the AnyVolumeDataSource feature gate
+ is enabled, this field will always have the same
+ contents as the DataSourceRef field.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is
+ required.
+ type: string
+ kind:
+ description: Kind is the type of resource being
+ referenced
+ type: string
+ name:
+ description: Name is the name of resource being
+ referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ dataSourceRef:
+ description: 'dataSourceRef specifies the object from
+ which to populate the volume with data, if a non-empty
+ volume is desired. This may be any local object
+ from a non-empty API group (non core object) or
+ a PersistentVolumeClaim object. When this field
+ is specified, volume binding will only succeed if
+ the type of the specified object matches some installed
+ volume populator or dynamic provisioner. This field
+ will replace the functionality of the DataSource
+ field and as such if both fields are non-empty,
+ they must have the same value. For backwards compatibility,
+ both fields (DataSource and DataSourceRef) will
+ be set to the same value automatically if one of
+ them is empty and the other is non-empty. There
+ are two important differences between DataSource
+ and DataSourceRef: * While DataSource only allows
+ two specific types of objects, DataSourceRef allows
+ any non-core object, as well as PersistentVolumeClaim
+ objects. * While DataSource ignores disallowed values
+ (dropping them), DataSourceRef preserves all values,
+ and generates an error if a disallowed value is
+ specified. (Beta) Using this field requires the
+ AnyVolumeDataSource feature gate to be enabled.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is
+ required.
+ type: string
+ kind:
+ description: Kind is the type of resource being
+ referenced
+ type: string
+ name:
+ description: Name is the name of resource being
+ referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ resources:
+ description: 'resources represents the minimum resources
+ the volume should have. If RecoverVolumeExpansionFailure
+ feature is enabled users are allowed to specify
+ resource requirements that are lower than previous
+ value but must still be higher than capacity recorded
+ in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount
+ of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount
+ of compute resources required. If Requests is
+ omitted for a container, it defaults to Limits
+ if that is explicitly specified, otherwise to
+ an implementation-defined value. More info:
+ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ selector:
+ description: selector is a label query over volumes
+ to consider for binding.
+ 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
+ x-kubernetes-map-type: atomic
+ storageClassName:
+ description: 'storageClassName is the name of the
+ StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
+ type: string
+ volumeMode:
+ description: volumeMode defines what type of volume
+ is required by the claim. Value of Filesystem is
+ implied when not included in claim spec.
+ type: string
+ volumeName:
+ description: volumeName is the binding reference to
+ the PersistentVolume backing this claim.
+ type: string
+ type: object
+ required:
+ - spec
+ type: object
+ type: object
+ volumeClaimTemplate:
+ description: A PVC spec to be used by the Prometheus StatefulSets.
+ 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:
+ description: EmbeddedMetadata contains metadata relevant to
+ an EmbeddedResource.
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: 'Annotations is an unstructured key value
+ map stored with a resource that may be set by external
+ tools to store and retrieve arbitrary metadata. They
+ are not queryable and should be preserved when modifying
+ objects. More info: http://kubernetes.io/docs/user-guide/annotations'
+ type: object
+ labels:
+ additionalProperties:
+ type: string
+ description: 'Map of string keys and values that can be
+ used to organize and categorize (scope and select) objects.
+ May match selectors of replication controllers and services.
+ More info: http://kubernetes.io/docs/user-guide/labels'
+ type: object
+ name:
+ description: 'Name must be unique within a namespace.
+ Is required when creating resources, although some resources
+ may allow a client to request the generation of an appropriate
+ name automatically. Name is primarily intended for creation
+ idempotence and configuration definition. Cannot be
+ updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names'
+ type: string
+ type: object
+ spec:
+ description: 'Spec defines the desired characteristics of
+ a volume requested by a pod author. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
+ properties:
+ accessModes:
+ description: 'accessModes contains the desired access
+ modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+ items:
+ type: string
+ type: array
+ dataSource:
+ description: 'dataSource field can be used to specify
+ either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
+ * An existing PVC (PersistentVolumeClaim) If the provisioner
+ or an external controller can support the specified
+ data source, it will create a new volume based on the
+ contents of the specified data source. If the AnyVolumeDataSource
+ feature gate is enabled, this field will always have
+ the same contents as the DataSourceRef field.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is required.
+ type: string
+ kind:
+ description: Kind is the type of resource being referenced
+ type: string
+ name:
+ description: Name is the name of resource being referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ dataSourceRef:
+ description: 'dataSourceRef specifies the object from
+ which to populate the volume with data, if a non-empty
+ volume is desired. This may be any local object from
+ a non-empty API group (non core object) or a PersistentVolumeClaim
+ object. When this field is specified, volume binding
+ will only succeed if the type of the specified object
+ matches some installed volume populator or dynamic provisioner.
+ This field will replace the functionality of the DataSource
+ field and as such if both fields are non-empty, they
+ must have the same value. For backwards compatibility,
+ both fields (DataSource and DataSourceRef) will be set
+ to the same value automatically if one of them is empty
+ and the other is non-empty. There are two important
+ differences between DataSource and DataSourceRef: *
+ While DataSource only allows two specific types of objects,
+ DataSourceRef allows any non-core object, as well as
+ PersistentVolumeClaim objects. * While DataSource ignores
+ disallowed values (dropping them), DataSourceRef preserves
+ all values, and generates an error if a disallowed value
+ is specified. (Beta) Using this field requires the AnyVolumeDataSource
+ feature gate to be enabled.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is required.
+ type: string
+ kind:
+ description: Kind is the type of resource being referenced
+ type: string
+ name:
+ description: Name is the name of resource being referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ resources:
+ description: 'resources represents the minimum resources
+ the volume should have. If RecoverVolumeExpansionFailure
+ feature is enabled users are allowed to specify resource
+ requirements that are lower than previous value but
+ must still be higher than capacity recorded in the status
+ field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount
+ of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount
+ of compute resources required. If Requests is omitted
+ for a container, it defaults to Limits if that is
+ explicitly specified, otherwise to an implementation-defined
+ value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ selector:
+ description: selector is a label query over volumes to
+ consider for binding.
+ 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
+ x-kubernetes-map-type: atomic
+ storageClassName:
+ description: 'storageClassName is the name of the StorageClass
+ required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
+ type: string
+ volumeMode:
+ description: volumeMode defines what type of volume is
+ required by the claim. Value of Filesystem is implied
+ when not included in claim spec.
+ type: string
+ volumeName:
+ description: volumeName is the binding reference to the
+ PersistentVolume backing this claim.
+ type: string
+ type: object
+ status:
+ description: 'Status represents the current information/status
+ of a persistent volume claim. Read-only. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
+ properties:
+ accessModes:
+ description: 'accessModes contains the actual access modes
+ the volume backing the PVC has. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+ items:
+ type: string
+ type: array
+ allocatedResources:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: allocatedResources is the storage resource
+ within AllocatedResources tracks the capacity allocated
+ to a PVC. It may be larger than the actual capacity
+ when a volume expansion operation is requested. For
+ storage quota, the larger value from allocatedResources
+ and PVC.spec.resources is used. If allocatedResources
+ is not set, PVC.spec.resources alone is used for quota
+ calculation. If a volume expansion capacity request
+ is lowered, allocatedResources is only lowered if there
+ are no expansion operations in progress and if the actual
+ volume capacity is equal or lower than the requested
+ capacity. This is an alpha field and requires enabling
+ RecoverVolumeExpansionFailure feature.
+ type: object
+ capacity:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: capacity represents the actual resources
+ of the underlying volume.
+ type: object
+ conditions:
+ description: conditions is the current Condition of persistent
+ volume claim. If underlying persistent volume is being
+ resized then the Condition will be set to 'ResizeStarted'.
+ items:
+ description: PersistentVolumeClaimCondition contails
+ details about state of pvc
+ properties:
+ lastProbeTime:
+ description: lastProbeTime is the time we probed
+ the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: lastTransitionTime is the time the
+ condition transitioned from one status to another.
+ format: date-time
+ type: string
+ message:
+ description: message is the human-readable message
+ indicating details about last transition.
+ type: string
+ reason:
+ description: reason is a unique, this should be
+ a short, machine understandable string that gives
+ the reason for condition's last transition. If
+ it reports "ResizeStarted" that means the underlying
+ persistent volume is being resized.
+ type: string
+ status:
+ type: string
+ type:
+ description: PersistentVolumeClaimConditionType
+ is a valid value of PersistentVolumeClaimCondition.Type
+ type: string
+ required:
+ - status
+ - type
+ type: object
+ type: array
+ phase:
+ description: phase represents the current phase of PersistentVolumeClaim.
+ type: string
+ resizeStatus:
+ description: resizeStatus stores status of resize operation.
+ ResizeStatus is not set by default but when expansion
+ is complete resizeStatus is set to empty string by resize
+ controller or kubelet. This is an alpha field and requires
+ enabling RecoverVolumeExpansionFailure feature.
+ type: string
+ type: object
+ type: object
+ type: object
+ tag:
+ description: 'Tag of Alertmanager container image to be deployed.
+ Defaults to the value of `version`. Version is ignored if Tag is
+ set. Deprecated: use ''image'' instead. The image tag can be specified
+ as part of the image URL.'
+ type: string
+ tolerations:
+ description: If specified, the pod's tolerations.
+ items:
+ description: The pod this Toleration is attached to tolerates any
+ taint that matches the triple using the matching
+ operator .
+ properties:
+ effect:
+ description: Effect indicates the taint effect to match. Empty
+ means match all taint effects. When specified, allowed values
+ are NoSchedule, PreferNoSchedule and NoExecute.
+ type: string
+ key:
+ description: Key is the taint key that the toleration applies
+ to. Empty means match all taint keys. If the key is empty,
+ operator must be Exists; this combination means to match all
+ values and all keys.
+ type: string
+ operator:
+ description: Operator represents a key's relationship to the
+ value. Valid operators are Exists and Equal. Defaults to Equal.
+ Exists is equivalent to wildcard for value, so that a pod
+ can tolerate all taints of a particular category.
+ type: string
+ tolerationSeconds:
+ description: TolerationSeconds represents the period of time
+ the toleration (which must be of effect NoExecute, otherwise
+ this field is ignored) tolerates the taint. By default, it
+ is not set, which means tolerate the taint forever (do not
+ evict). Zero and negative values will be treated as 0 (evict
+ immediately) by the system.
+ format: int64
+ type: integer
+ value:
+ description: Value is the taint value the toleration matches
+ to. If the operator is Exists, the value should be empty,
+ otherwise just a regular string.
+ type: string
+ type: object
+ type: array
+ topologySpreadConstraints:
+ description: If specified, the pod's topology spread constraints.
+ items:
+ description: TopologySpreadConstraint specifies how to spread matching
+ pods among the given topology.
+ properties:
+ labelSelector:
+ description: LabelSelector is used to find matching pods. Pods
+ that match this label selector are counted to determine the
+ number of pods in their corresponding topology domain.
+ 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
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: MatchLabelKeys is a set of pod label keys to select
+ the pods over which spreading will be calculated. The keys
+ are used to lookup values from the incoming pod labels, those
+ key-value labels are ANDed with labelSelector to select the
+ group of existing pods over which spreading will be calculated
+ for the incoming pod. Keys that don't exist in the incoming
+ pod labels will be ignored. A null or empty list means only
+ match against labelSelector.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ maxSkew:
+ description: 'MaxSkew describes the degree to which pods may
+ be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`,
+ it is the maximum permitted difference between the number
+ of matching pods in the target topology and the global minimum.
+ The global minimum is the minimum number of matching pods
+ in an eligible domain or zero if the number of eligible domains
+ is less than MinDomains. For example, in a 3-zone cluster,
+ MaxSkew is set to 1, and pods with the same labelSelector
+ spread as 2/2/1: In this case, the global minimum is 1. |
+ zone1 | zone2 | zone3 | | P P | P P | P | - if MaxSkew
+ is 1, incoming pod can only be scheduled to zone3 to become
+ 2/2/2; scheduling it onto zone1(zone2) would make the ActualSkew(3-1)
+ on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming
+ pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`,
+ it is used to give higher precedence to topologies that satisfy
+ it. It''s a required field. Default value is 1 and 0 is not
+ allowed.'
+ format: int32
+ type: integer
+ minDomains:
+ description: "MinDomains indicates a minimum number of eligible
+ domains. When the number of eligible domains with matching
+ topology keys is less than minDomains, Pod Topology Spread
+ treats \"global minimum\" as 0, and then the calculation of
+ Skew is performed. And when the number of eligible domains
+ with matching topology keys equals or greater than minDomains,
+ this value has no effect on scheduling. As a result, when
+ the number of eligible domains is less than minDomains, scheduler
+ won't schedule more than maxSkew Pods to those domains. If
+ value is nil, the constraint behaves as if MinDomains is equal
+ to 1. Valid values are integers greater than 0. When value
+ is not nil, WhenUnsatisfiable must be DoNotSchedule. \n For
+ example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains
+ is set to 5 and pods with the same labelSelector spread as
+ 2/2/2: | zone1 | zone2 | zone3 | | P P | P P | P P |
+ The number of domains is less than 5(MinDomains), so \"global
+ minimum\" is treated as 0. In this situation, new pod with
+ the same labelSelector cannot be scheduled, because computed
+ skew will be 3(3 - 0) if new Pod is scheduled to any of the
+ three zones, it will violate MaxSkew. \n This is a beta field
+ and requires the MinDomainsInPodTopologySpread feature gate
+ to be enabled (enabled by default)."
+ format: int32
+ type: integer
+ nodeAffinityPolicy:
+ description: "NodeAffinityPolicy indicates how we will treat
+ Pod's nodeAffinity/nodeSelector when calculating pod topology
+ spread skew. Options are: - Honor: only nodes matching nodeAffinity/nodeSelector
+ are included in the calculations. - Ignore: nodeAffinity/nodeSelector
+ are ignored. All nodes are included in the calculations. \n
+ If this value is nil, the behavior is equivalent to the Honor
+ policy. This is a alpha-level feature enabled by the NodeInclusionPolicyInPodTopologySpread
+ feature flag."
+ type: string
+ nodeTaintsPolicy:
+ description: "NodeTaintsPolicy indicates how we will treat node
+ taints when calculating pod topology spread skew. Options
+ are: - Honor: nodes without taints, along with tainted nodes
+ for which the incoming pod has a toleration, are included.
+ - Ignore: node taints are ignored. All nodes are included.
+ \n If this value is nil, the behavior is equivalent to the
+ Ignore policy. This is a alpha-level feature enabled by the
+ NodeInclusionPolicyInPodTopologySpread feature flag."
+ type: string
+ topologyKey:
+ description: TopologyKey is the key of node labels. Nodes that
+ have a label with this key and identical values are considered
+ to be in the same topology. We consider each
+ as a "bucket", and try to put balanced number of pods into
+ each bucket. We define a domain as a particular instance of
+ a topology. Also, we define an eligible domain as a domain
+ whose nodes meet the requirements of nodeAffinityPolicy and
+ nodeTaintsPolicy. e.g. If TopologyKey is "kubernetes.io/hostname",
+ each Node is a domain of that topology. And, if TopologyKey
+ is "topology.kubernetes.io/zone", each zone is a domain of
+ that topology. It's a required field.
+ type: string
+ whenUnsatisfiable:
+ description: 'WhenUnsatisfiable indicates how to deal with a
+ pod if it doesn''t satisfy the spread constraint. - DoNotSchedule
+ (default) tells the scheduler not to schedule it. - ScheduleAnyway
+ tells the scheduler to schedule the pod in any location, but
+ giving higher precedence to topologies that would help reduce
+ the skew. A constraint is considered "Unsatisfiable" for an
+ incoming pod if and only if every possible node assignment
+ for that pod would violate "MaxSkew" on some topology. For
+ example, in a 3-zone cluster, MaxSkew is set to 1, and pods
+ with the same labelSelector spread as 3/1/1: | zone1 | zone2
+ | zone3 | | P P P | P | P | If WhenUnsatisfiable is
+ set to DoNotSchedule, incoming pod can only be scheduled to
+ zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on
+ zone2(zone3) satisfies MaxSkew(1). In other words, the cluster
+ can still be imbalanced, but scheduler won''t make it *more*
+ imbalanced. It''s a required field.'
+ type: string
+ required:
+ - maxSkew
+ - topologyKey
+ - whenUnsatisfiable
+ type: object
+ type: array
+ version:
+ description: Version the cluster should be on.
+ type: string
+ volumeMounts:
+ description: VolumeMounts allows configuration of additional VolumeMounts
+ on the output StatefulSet definition. VolumeMounts specified will
+ be appended to other VolumeMounts in the alertmanager container,
+ that are generated as a result of StorageSpec objects.
+ items:
+ description: VolumeMount describes a mounting of a Volume within
+ a container.
+ properties:
+ mountPath:
+ description: Path within the container at which the volume should
+ be mounted. Must not contain ':'.
+ type: string
+ mountPropagation:
+ description: mountPropagation determines how mounts are propagated
+ from the host to container and the other way around. When
+ not set, MountPropagationNone is used. This field is beta
+ in 1.10.
+ type: string
+ name:
+ description: This must match the Name of a Volume.
+ type: string
+ readOnly:
+ description: Mounted read-only if true, read-write otherwise
+ (false or unspecified). Defaults to false.
+ type: boolean
+ subPath:
+ description: Path within the volume from which the container's
+ volume should be mounted. Defaults to "" (volume's root).
+ type: string
+ subPathExpr:
+ description: Expanded path within the volume from which the
+ container's volume should be mounted. Behaves similarly to
+ SubPath but environment variable references $(VAR_NAME) are
+ expanded using the container's environment. Defaults to ""
+ (volume's root). SubPathExpr and SubPath are mutually exclusive.
+ type: string
+ required:
+ - mountPath
+ - name
+ type: object
+ type: array
+ volumes:
+ description: Volumes allows configuration of additional volumes on
+ the output StatefulSet definition. Volumes specified will be appended
+ to other volumes that are generated as a result of StorageSpec objects.
+ items:
+ description: Volume represents a named volume in a pod that may
+ be accessed by any container in the pod.
+ properties:
+ awsElasticBlockStore:
+ description: 'awsElasticBlockStore represents an AWS Disk resource
+ that is attached to a kubelet''s host machine and then exposed
+ to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore'
+ properties:
+ fsType:
+ description: 'fsType is the filesystem type of the volume
+ that you want to mount. Tip: Ensure that the filesystem
+ type is supported by the host operating system. Examples:
+ "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore
+ TODO: how do we prevent errors in the filesystem from
+ compromising the machine'
+ type: string
+ partition:
+ description: 'partition is the partition in the volume that
+ you want to mount. If omitted, the default is to mount
+ by volume name. Examples: For volume /dev/sda1, you specify
+ the partition as "1". Similarly, the volume partition
+ for /dev/sda is "0" (or you can leave the property empty).'
+ format: int32
+ type: integer
+ readOnly:
+ description: 'readOnly value true will force the readOnly
+ setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore'
+ type: boolean
+ volumeID:
+ description: 'volumeID is unique ID of the persistent disk
+ resource in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore'
+ type: string
+ required:
+ - volumeID
+ type: object
+ azureDisk:
+ description: azureDisk represents an Azure Data Disk mount on
+ the host and bind mount to the pod.
+ properties:
+ cachingMode:
+ description: 'cachingMode is the Host Caching mode: None,
+ Read Only, Read Write.'
+ type: string
+ diskName:
+ description: diskName is the Name of the data disk in the
+ blob storage
+ type: string
+ diskURI:
+ description: diskURI is the URI of data disk in the blob
+ storage
+ type: string
+ fsType:
+ description: fsType is Filesystem type to mount. Must be
+ a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ kind:
+ description: 'kind expected values are Shared: multiple
+ blob disks per storage account Dedicated: single blob
+ disk per storage account Managed: azure managed data
+ disk (only in managed availability set). defaults to shared'
+ type: string
+ readOnly:
+ description: readOnly Defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ required:
+ - diskName
+ - diskURI
+ type: object
+ azureFile:
+ description: azureFile represents an Azure File Service mount
+ on the host and bind mount to the pod.
+ properties:
+ readOnly:
+ description: readOnly defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretName:
+ description: secretName is the name of secret that contains
+ Azure Storage Account Name and Key
+ type: string
+ shareName:
+ description: shareName is the azure share Name
+ type: string
+ required:
+ - secretName
+ - shareName
+ type: object
+ cephfs:
+ description: cephFS represents a Ceph FS mount on the host that
+ shares a pod's lifetime
+ properties:
+ monitors:
+ description: 'monitors is Required: Monitors is a collection
+ of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ items:
+ type: string
+ type: array
+ path:
+ description: 'path is Optional: Used as the mounted root,
+ rather than the full Ceph tree, default is /'
+ type: string
+ readOnly:
+ description: 'readOnly is Optional: Defaults to false (read/write).
+ ReadOnly here will force the ReadOnly setting in VolumeMounts.
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ type: boolean
+ secretFile:
+ description: 'secretFile is Optional: SecretFile is the
+ path to key ring for User, default is /etc/ceph/user.secret
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ type: string
+ secretRef:
+ description: 'secretRef is Optional: SecretRef is reference
+ to the authentication secret for User, default is empty.
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ user:
+ description: 'user is optional: User is the rados user name,
+ default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ type: string
+ required:
+ - monitors
+ type: object
+ cinder:
+ description: 'cinder represents a cinder volume attached and
+ mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md'
+ properties:
+ fsType:
+ description: 'fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Examples: "ext4", "xfs", "ntfs". Implicitly inferred to
+ be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md'
+ type: string
+ readOnly:
+ description: 'readOnly defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ More info: https://examples.k8s.io/mysql-cinder-pd/README.md'
+ type: boolean
+ secretRef:
+ description: 'secretRef is optional: points to a secret
+ object containing parameters used to connect to OpenStack.'
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ volumeID:
+ description: 'volumeID used to identify the volume in cinder.
+ More info: https://examples.k8s.io/mysql-cinder-pd/README.md'
+ type: string
+ required:
+ - volumeID
+ type: object
+ configMap:
+ description: configMap represents a configMap that should populate
+ this volume
+ properties:
+ defaultMode:
+ description: 'defaultMode is optional: mode bits used to
+ set permissions on created files by default. Must be an
+ octal value between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. Defaults to
+ 0644. Directories within the path are not affected by
+ this setting. This might be in conflict with other options
+ that affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ items:
+ description: items if unspecified, each key-value pair in
+ the Data field of the referenced ConfigMap will be projected
+ into the volume as a file whose name is the key and content
+ is the value. If specified, the listed keys will be projected
+ into the specified paths, and unlisted keys will not be
+ present. If a key is specified which is not present in
+ the ConfigMap, the volume setup will error unless it is
+ marked optional. Paths must be relative and may not contain
+ the '..' path or start with '..'.
+ items:
+ description: Maps a string key to a path within a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: 'mode is Optional: mode bits used to
+ set permissions on this file. Must be an octal value
+ between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. If not
+ specified, the volume defaultMode will be used.
+ This might be in conflict with other options that
+ affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: path is the relative path of the file
+ to map the key to. May not be an absolute path.
+ May not contain the path element '..'. May not start
+ with the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: optional specify whether the ConfigMap or its
+ keys must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ csi:
+ description: csi (Container Storage Interface) represents ephemeral
+ storage that is handled by certain external CSI drivers (Beta
+ feature).
+ properties:
+ driver:
+ description: driver is the name of the CSI driver that handles
+ this volume. Consult with your admin for the correct name
+ as registered in the cluster.
+ type: string
+ fsType:
+ description: fsType to mount. Ex. "ext4", "xfs", "ntfs".
+ If not provided, the empty value is passed to the associated
+ CSI driver which will determine the default filesystem
+ to apply.
+ type: string
+ nodePublishSecretRef:
+ description: nodePublishSecretRef is a reference to the
+ secret object containing sensitive information to pass
+ to the CSI driver to complete the CSI NodePublishVolume
+ and NodeUnpublishVolume calls. This field is optional,
+ and may be empty if no secret is required. If the secret
+ object contains more than one secret, all secret references
+ are passed.
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ readOnly:
+ description: readOnly specifies a read-only configuration
+ for the volume. Defaults to false (read/write).
+ type: boolean
+ volumeAttributes:
+ additionalProperties:
+ type: string
+ description: volumeAttributes stores driver-specific properties
+ that are passed to the CSI driver. Consult your driver's
+ documentation for supported values.
+ type: object
+ required:
+ - driver
+ type: object
+ downwardAPI:
+ description: downwardAPI represents downward API about the pod
+ that should populate this volume
+ properties:
+ defaultMode:
+ description: 'Optional: mode bits to use on created files
+ by default. Must be a Optional: mode bits used to set
+ permissions on created files by default. Must be an octal
+ value between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. Defaults to
+ 0644. Directories within the path are not affected by
+ this setting. This might be in conflict with other options
+ that affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ items:
+ description: Items is a list of downward API volume file
+ items:
+ description: DownwardAPIVolumeFile represents information
+ to create the file containing the pod field
+ properties:
+ fieldRef:
+ description: 'Required: Selects a field of the pod:
+ only annotations, labels, name and namespace are
+ supported.'
+ properties:
+ apiVersion:
+ description: Version of the schema the FieldPath
+ is written in terms of, defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select in the
+ specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ mode:
+ description: 'Optional: mode bits used to set permissions
+ on this file, must be an octal value between 0000
+ and 0777 or a decimal value between 0 and 511. YAML
+ accepts both octal and decimal values, JSON requires
+ decimal values for mode bits. If not specified,
+ the volume defaultMode will be used. This might
+ be in conflict with other options that affect the
+ file mode, like fsGroup, and the result can be other
+ mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: 'Required: Path is the relative path
+ name of the file to be created. Must not be absolute
+ or contain the ''..'' path. Must be utf-8 encoded.
+ The first item of the relative path must not start
+ with ''..'''
+ type: string
+ resourceFieldRef:
+ description: 'Selects a resource of the container:
+ only resources limits and requests (limits.cpu,
+ limits.memory, requests.cpu and requests.memory)
+ are currently supported.'
+ properties:
+ containerName:
+ description: 'Container name: required for volumes,
+ optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format of the
+ exposed resources, defaults to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ required:
+ - path
+ type: object
+ type: array
+ type: object
+ emptyDir:
+ description: 'emptyDir represents a temporary directory that
+ shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir'
+ properties:
+ medium:
+ description: 'medium represents what type of storage medium
+ should back this directory. The default is "" which means
+ to use the node''s default medium. Must be an empty string
+ (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir'
+ type: string
+ sizeLimit:
+ anyOf:
+ - type: integer
+ - type: string
+ description: 'sizeLimit is the total amount of local storage
+ required for this EmptyDir volume. The size limit is also
+ applicable for memory medium. The maximum usage on memory
+ medium EmptyDir would be the minimum value between the
+ SizeLimit specified here and the sum of memory limits
+ of all containers in a pod. The default is nil which means
+ that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir'
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type: object
+ ephemeral:
+ description: "ephemeral represents a volume that is handled
+ by a cluster storage driver. The volume's lifecycle is tied
+ to the pod that defines it - it will be created before the
+ pod starts, and deleted when the pod is removed. \n Use this
+ if: a) the volume is only needed while the pod runs, b) features
+ of normal volumes like restoring from snapshot or capacity
+ tracking are needed, c) the storage driver is specified through
+ a storage class, and d) the storage driver supports dynamic
+ volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource
+ for more information on the connection between this volume
+ type and PersistentVolumeClaim). \n Use PersistentVolumeClaim
+ or one of the vendor-specific APIs for volumes that persist
+ for longer than the lifecycle of an individual pod. \n Use
+ CSI for light-weight local ephemeral volumes if the CSI driver
+ is meant to be used that way - see the documentation of the
+ driver for more information. \n A pod can use both types of
+ ephemeral volumes and persistent volumes at the same time."
+ properties:
+ volumeClaimTemplate:
+ description: "Will be used to create a stand-alone PVC to
+ provision the volume. The pod in which this EphemeralVolumeSource
+ is embedded will be the owner of the PVC, i.e. the PVC
+ will be deleted together with the pod. The name of the
+ PVC will be `-` where `` is the name from the `PodSpec.Volumes` array entry.
+ Pod validation will reject the pod if the concatenated
+ name is not valid for a PVC (for example, too long). \n
+ An existing PVC with that name that is not owned by the
+ pod will *not* be used for the pod to avoid using an unrelated
+ volume by mistake. Starting the pod is then blocked until
+ the unrelated PVC is removed. If such a pre-created PVC
+ is meant to be used by the pod, the PVC has to updated
+ with an owner reference to the pod once the pod exists.
+ Normally this should not be necessary, but it may be useful
+ when manually reconstructing a broken cluster. \n This
+ field is read-only and no changes will be made by Kubernetes
+ to the PVC after it has been created. \n Required, must
+ not be nil."
+ properties:
+ metadata:
+ description: May contain labels and annotations that
+ will be copied into the PVC when creating it. No other
+ fields are allowed and will be rejected during validation.
+ type: object
+ spec:
+ description: The specification for the PersistentVolumeClaim.
+ The entire content is copied unchanged into the PVC
+ that gets created from this template. The same fields
+ as in a PersistentVolumeClaim are also valid here.
+ properties:
+ accessModes:
+ description: 'accessModes contains the desired access
+ modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+ items:
+ type: string
+ type: array
+ dataSource:
+ description: 'dataSource field can be used to specify
+ either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
+ * An existing PVC (PersistentVolumeClaim) If the
+ provisioner or an external controller can support
+ the specified data source, it will create a new
+ volume based on the contents of the specified
+ data source. If the AnyVolumeDataSource feature
+ gate is enabled, this field will always have the
+ same contents as the DataSourceRef field.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API
+ group. For any other third-party types, APIGroup
+ is required.
+ type: string
+ kind:
+ description: Kind is the type of resource being
+ referenced
+ type: string
+ name:
+ description: Name is the name of resource being
+ referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ dataSourceRef:
+ description: 'dataSourceRef specifies the object
+ from which to populate the volume with data, if
+ a non-empty volume is desired. This may be any
+ local object from a non-empty API group (non core
+ object) or a PersistentVolumeClaim object. When
+ this field is specified, volume binding will only
+ succeed if the type of the specified object matches
+ some installed volume populator or dynamic provisioner.
+ This field will replace the functionality of the
+ DataSource field and as such if both fields are
+ non-empty, they must have the same value. For
+ backwards compatibility, both fields (DataSource
+ and DataSourceRef) will be set to the same value
+ automatically if one of them is empty and the
+ other is non-empty. There are two important differences
+ between DataSource and DataSourceRef: * While
+ DataSource only allows two specific types of objects,
+ DataSourceRef allows any non-core object, as well
+ as PersistentVolumeClaim objects. * While DataSource
+ ignores disallowed values (dropping them), DataSourceRef
+ preserves all values, and generates an error if
+ a disallowed value is specified. (Beta) Using
+ this field requires the AnyVolumeDataSource feature
+ gate to be enabled.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API
+ group. For any other third-party types, APIGroup
+ is required.
+ type: string
+ kind:
+ description: Kind is the type of resource being
+ referenced
+ type: string
+ name:
+ description: Name is the name of resource being
+ referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ resources:
+ description: 'resources represents the minimum resources
+ the volume should have. If RecoverVolumeExpansionFailure
+ feature is enabled users are allowed to specify
+ resource requirements that are lower than previous
+ value but must still be higher than capacity recorded
+ in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount
+ of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum
+ amount of compute resources required. If Requests
+ is omitted for a container, it defaults to
+ Limits if that is explicitly specified, otherwise
+ to an implementation-defined value. More info:
+ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ selector:
+ description: selector is a label query over volumes
+ to consider for binding.
+ 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
+ x-kubernetes-map-type: atomic
+ storageClassName:
+ description: 'storageClassName is the name of the
+ StorageClass required by the claim. More info:
+ https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
+ type: string
+ volumeMode:
+ description: volumeMode defines what type of volume
+ is required by the claim. Value of Filesystem
+ is implied when not included in claim spec.
+ type: string
+ volumeName:
+ description: volumeName is the binding reference
+ to the PersistentVolume backing this claim.
+ type: string
+ type: object
+ required:
+ - spec
+ type: object
+ type: object
+ fc:
+ description: fc represents a Fibre Channel resource that is
+ attached to a kubelet's host machine and then exposed to the
+ pod.
+ properties:
+ fsType:
+ description: 'fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified. TODO: how do we prevent errors in the
+ filesystem from compromising the machine'
+ type: string
+ lun:
+ description: 'lun is Optional: FC target lun number'
+ format: int32
+ type: integer
+ readOnly:
+ description: 'readOnly is Optional: Defaults to false (read/write).
+ ReadOnly here will force the ReadOnly setting in VolumeMounts.'
+ type: boolean
+ targetWWNs:
+ description: 'targetWWNs is Optional: FC target worldwide
+ names (WWNs)'
+ items:
+ type: string
+ type: array
+ wwids:
+ description: 'wwids Optional: FC volume world wide identifiers
+ (wwids) Either wwids or combination of targetWWNs and
+ lun must be set, but not both simultaneously.'
+ items:
+ type: string
+ type: array
+ type: object
+ flexVolume:
+ description: flexVolume represents a generic volume resource
+ that is provisioned/attached using an exec based plugin.
+ properties:
+ driver:
+ description: driver is the name of the driver to use for
+ this volume.
+ type: string
+ fsType:
+ description: fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". The default filesystem depends
+ on FlexVolume script.
+ type: string
+ options:
+ additionalProperties:
+ type: string
+ description: 'options is Optional: this field holds extra
+ command options if any.'
+ type: object
+ readOnly:
+ description: 'readOnly is Optional: defaults to false (read/write).
+ ReadOnly here will force the ReadOnly setting in VolumeMounts.'
+ type: boolean
+ secretRef:
+ description: 'secretRef is Optional: secretRef is reference
+ to the secret object containing sensitive information
+ to pass to the plugin scripts. This may be empty if no
+ secret object is specified. If the secret object contains
+ more than one secret, all secrets are passed to the plugin
+ scripts.'
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ required:
+ - driver
+ type: object
+ flocker:
+ description: flocker represents a Flocker volume attached to
+ a kubelet's host machine. This depends on the Flocker control
+ service being running
+ properties:
+ datasetName:
+ description: datasetName is Name of the dataset stored as
+ metadata -> name on the dataset for Flocker should be
+ considered as deprecated
+ type: string
+ datasetUUID:
+ description: datasetUUID is the UUID of the dataset. This
+ is unique identifier of a Flocker dataset
+ type: string
+ type: object
+ gcePersistentDisk:
+ description: 'gcePersistentDisk represents a GCE Disk resource
+ that is attached to a kubelet''s host machine and then exposed
+ to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk'
+ properties:
+ fsType:
+ description: 'fsType is filesystem type of the volume that
+ you want to mount. Tip: Ensure that the filesystem type
+ is supported by the host operating system. Examples: "ext4",
+ "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk
+ TODO: how do we prevent errors in the filesystem from
+ compromising the machine'
+ type: string
+ partition:
+ description: 'partition is the partition in the volume that
+ you want to mount. If omitted, the default is to mount
+ by volume name. Examples: For volume /dev/sda1, you specify
+ the partition as "1". Similarly, the volume partition
+ for /dev/sda is "0" (or you can leave the property empty).
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk'
+ format: int32
+ type: integer
+ pdName:
+ description: 'pdName is unique name of the PD resource in
+ GCE. Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk'
+ type: string
+ readOnly:
+ description: 'readOnly here will force the ReadOnly setting
+ in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk'
+ type: boolean
+ required:
+ - pdName
+ type: object
+ gitRepo:
+ description: 'gitRepo represents a git repository at a particular
+ revision. DEPRECATED: GitRepo is deprecated. To provision
+ a container with a git repo, mount an EmptyDir into an InitContainer
+ that clones the repo using git, then mount the EmptyDir into
+ the Pod''s container.'
+ properties:
+ directory:
+ description: directory is the target directory name. Must
+ not contain or start with '..'. If '.' is supplied, the
+ volume directory will be the git repository. Otherwise,
+ if specified, the volume will contain the git repository
+ in the subdirectory with the given name.
+ type: string
+ repository:
+ description: repository is the URL
+ type: string
+ revision:
+ description: revision is the commit hash for the specified
+ revision.
+ type: string
+ required:
+ - repository
+ type: object
+ glusterfs:
+ description: 'glusterfs represents a Glusterfs mount on the
+ host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md'
+ properties:
+ endpoints:
+ description: 'endpoints is the endpoint name that details
+ Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod'
+ type: string
+ path:
+ description: 'path is the Glusterfs volume path. More info:
+ https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod'
+ type: string
+ readOnly:
+ description: 'readOnly here will force the Glusterfs volume
+ to be mounted with read-only permissions. Defaults to
+ false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod'
+ type: boolean
+ required:
+ - endpoints
+ - path
+ type: object
+ hostPath:
+ description: 'hostPath represents a pre-existing file or directory
+ on the host machine that is directly exposed to the container.
+ This is generally used for system agents or other privileged
+ things that are allowed to see the host machine. Most containers
+ will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath
+ --- TODO(jonesdl) We need to restrict who can use host directory
+ mounts and who can/can not mount host directories as read/write.'
+ properties:
+ path:
+ description: 'path of the directory on the host. If the
+ path is a symlink, it will follow the link to the real
+ path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath'
+ type: string
+ type:
+ description: 'type for HostPath Volume Defaults to "" More
+ info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath'
+ type: string
+ required:
+ - path
+ type: object
+ iscsi:
+ description: 'iscsi represents an ISCSI Disk resource that is
+ attached to a kubelet''s host machine and then exposed to
+ the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md'
+ properties:
+ chapAuthDiscovery:
+ description: chapAuthDiscovery defines whether support iSCSI
+ Discovery CHAP authentication
+ type: boolean
+ chapAuthSession:
+ description: chapAuthSession defines whether support iSCSI
+ Session CHAP authentication
+ type: boolean
+ fsType:
+ description: 'fsType is the filesystem type of the volume
+ that you want to mount. Tip: Ensure that the filesystem
+ type is supported by the host operating system. Examples:
+ "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi
+ TODO: how do we prevent errors in the filesystem from
+ compromising the machine'
+ type: string
+ initiatorName:
+ description: initiatorName is the custom iSCSI Initiator
+ Name. If initiatorName is specified with iscsiInterface
+ simultaneously, new iSCSI interface : will be created for the connection.
+ type: string
+ iqn:
+ description: iqn is the target iSCSI Qualified Name.
+ type: string
+ iscsiInterface:
+ description: iscsiInterface is the interface Name that uses
+ an iSCSI transport. Defaults to 'default' (tcp).
+ type: string
+ lun:
+ description: lun represents iSCSI Target Lun number.
+ format: int32
+ type: integer
+ portals:
+ description: portals is the iSCSI Target Portal List. The
+ portal is either an IP or ip_addr:port if the port is
+ other than default (typically TCP ports 860 and 3260).
+ items:
+ type: string
+ type: array
+ readOnly:
+ description: readOnly here will force the ReadOnly setting
+ in VolumeMounts. Defaults to false.
+ type: boolean
+ secretRef:
+ description: secretRef is the CHAP Secret for iSCSI target
+ and initiator authentication
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ targetPortal:
+ description: targetPortal is iSCSI Target Portal. The Portal
+ is either an IP or ip_addr:port if the port is other than
+ default (typically TCP ports 860 and 3260).
+ type: string
+ required:
+ - iqn
+ - lun
+ - targetPortal
+ type: object
+ name:
+ description: 'name of the volume. Must be a DNS_LABEL and unique
+ within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
+ type: string
+ nfs:
+ description: 'nfs represents an NFS mount on the host that shares
+ a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs'
+ properties:
+ path:
+ description: 'path that is exported by the NFS server. More
+ info: https://kubernetes.io/docs/concepts/storage/volumes#nfs'
+ type: string
+ readOnly:
+ description: 'readOnly here will force the NFS export to
+ be mounted with read-only permissions. Defaults to false.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs'
+ type: boolean
+ server:
+ description: 'server is the hostname or IP address of the
+ NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs'
+ type: string
+ required:
+ - path
+ - server
+ type: object
+ persistentVolumeClaim:
+ description: 'persistentVolumeClaimVolumeSource represents a
+ reference to a PersistentVolumeClaim in the same namespace.
+ More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
+ properties:
+ claimName:
+ description: 'claimName is the name of a PersistentVolumeClaim
+ in the same namespace as the pod using this volume. More
+ info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
+ type: string
+ readOnly:
+ description: readOnly Will force the ReadOnly setting in
+ VolumeMounts. Default false.
+ type: boolean
+ required:
+ - claimName
+ type: object
+ photonPersistentDisk:
+ description: photonPersistentDisk represents a PhotonController
+ persistent disk attached and mounted on kubelets host machine
+ properties:
+ fsType:
+ description: fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ pdID:
+ description: pdID is the ID that identifies Photon Controller
+ persistent disk
+ type: string
+ required:
+ - pdID
+ type: object
+ portworxVolume:
+ description: portworxVolume represents a portworx volume attached
+ and mounted on kubelets host machine
+ properties:
+ fsType:
+ description: fSType represents the filesystem type to mount
+ Must be a filesystem type supported by the host operating
+ system. Ex. "ext4", "xfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ readOnly:
+ description: readOnly defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ volumeID:
+ description: volumeID uniquely identifies a Portworx volume
+ type: string
+ required:
+ - volumeID
+ type: object
+ projected:
+ description: projected items for all in one resources secrets,
+ configmaps, and downward API
+ properties:
+ defaultMode:
+ description: defaultMode are the mode bits used to set permissions
+ on created files by default. Must be an octal value between
+ 0000 and 0777 or a decimal value between 0 and 511. YAML
+ accepts both octal and decimal values, JSON requires decimal
+ values for mode bits. Directories within the path are
+ not affected by this setting. This might be in conflict
+ with other options that affect the file mode, like fsGroup,
+ and the result can be other mode bits set.
+ format: int32
+ type: integer
+ sources:
+ description: sources is the list of volume projections
+ items:
+ description: Projection that may be projected along with
+ other supported volume types
+ properties:
+ configMap:
+ description: configMap information about the configMap
+ data to project
+ properties:
+ items:
+ description: items if unspecified, each key-value
+ pair in the Data field of the referenced ConfigMap
+ will be projected into the volume as a file
+ whose name is the key and content is the value.
+ If specified, the listed keys will be projected
+ into the specified paths, and unlisted keys
+ will not be present. If a key is specified which
+ is not present in the ConfigMap, the volume
+ setup will error unless it is marked optional.
+ Paths must be relative and may not contain the
+ '..' path or start with '..'.
+ items:
+ description: Maps a string key to a path within
+ a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: 'mode is Optional: mode bits
+ used to set permissions on this file.
+ Must be an octal value between 0000 and
+ 0777 or a decimal value between 0 and
+ 511. YAML accepts both octal and decimal
+ values, JSON requires decimal values for
+ mode bits. If not specified, the volume
+ defaultMode will be used. This might be
+ in conflict with other options that affect
+ the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: path is the relative path of
+ the file to map the key to. May not be
+ an absolute path. May not contain the
+ path element '..'. May not start with
+ the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: optional specify whether the ConfigMap
+ or its keys must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ downwardAPI:
+ description: downwardAPI information about the downwardAPI
+ data to project
+ properties:
+ items:
+ description: Items is a list of DownwardAPIVolume
+ file
+ items:
+ description: DownwardAPIVolumeFile represents
+ information to create the file containing
+ the pod field
+ properties:
+ fieldRef:
+ description: 'Required: Selects a field
+ of the pod: only annotations, labels,
+ name and namespace are supported.'
+ properties:
+ apiVersion:
+ description: Version of the schema the
+ FieldPath is written in terms of,
+ defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select
+ in the specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ mode:
+ description: 'Optional: mode bits used to
+ set permissions on this file, must be
+ an octal value between 0000 and 0777 or
+ a decimal value between 0 and 511. YAML
+ accepts both octal and decimal values,
+ JSON requires decimal values for mode
+ bits. If not specified, the volume defaultMode
+ will be used. This might be in conflict
+ with other options that affect the file
+ mode, like fsGroup, and the result can
+ be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: 'Required: Path is the relative
+ path name of the file to be created. Must
+ not be absolute or contain the ''..''
+ path. Must be utf-8 encoded. The first
+ item of the relative path must not start
+ with ''..'''
+ type: string
+ resourceFieldRef:
+ description: 'Selects a resource of the
+ container: only resources limits and requests
+ (limits.cpu, limits.memory, requests.cpu
+ and requests.memory) are currently supported.'
+ properties:
+ containerName:
+ description: 'Container name: required
+ for volumes, optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format
+ of the exposed resources, defaults
+ to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to
+ select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ required:
+ - path
+ type: object
+ type: array
+ type: object
+ secret:
+ description: secret information about the secret data
+ to project
+ properties:
+ items:
+ description: items if unspecified, each key-value
+ pair in the Data field of the referenced Secret
+ will be projected into the volume as a file
+ whose name is the key and content is the value.
+ If specified, the listed keys will be projected
+ into the specified paths, and unlisted keys
+ will not be present. If a key is specified which
+ is not present in the Secret, the volume setup
+ will error unless it is marked optional. Paths
+ must be relative and may not contain the '..'
+ path or start with '..'.
+ items:
+ description: Maps a string key to a path within
+ a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: 'mode is Optional: mode bits
+ used to set permissions on this file.
+ Must be an octal value between 0000 and
+ 0777 or a decimal value between 0 and
+ 511. YAML accepts both octal and decimal
+ values, JSON requires decimal values for
+ mode bits. If not specified, the volume
+ defaultMode will be used. This might be
+ in conflict with other options that affect
+ the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: path is the relative path of
+ the file to map the key to. May not be
+ an absolute path. May not contain the
+ path element '..'. May not start with
+ the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: optional field specify whether the
+ Secret or its key must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ serviceAccountToken:
+ description: serviceAccountToken is information about
+ the serviceAccountToken data to project
+ properties:
+ audience:
+ description: audience is the intended audience
+ of the token. A recipient of a token must identify
+ itself with an identifier specified in the audience
+ of the token, and otherwise should reject the
+ token. The audience defaults to the identifier
+ of the apiserver.
+ type: string
+ expirationSeconds:
+ description: expirationSeconds is the requested
+ duration of validity of the service account
+ token. As the token approaches expiration, the
+ kubelet volume plugin will proactively rotate
+ the service account token. The kubelet will
+ start trying to rotate the token if the token
+ is older than 80 percent of its time to live
+ or if the token is older than 24 hours.Defaults
+ to 1 hour and must be at least 10 minutes.
+ format: int64
+ type: integer
+ path:
+ description: path is the path relative to the
+ mount point of the file to project the token
+ into.
+ type: string
+ required:
+ - path
+ type: object
+ type: object
+ type: array
+ type: object
+ quobyte:
+ description: quobyte represents a Quobyte mount on the host
+ that shares a pod's lifetime
+ properties:
+ group:
+ description: group to map volume access to Default is no
+ group
+ type: string
+ readOnly:
+ description: readOnly here will force the Quobyte volume
+ to be mounted with read-only permissions. Defaults to
+ false.
+ type: boolean
+ registry:
+ description: registry represents a single or multiple Quobyte
+ Registry services specified as a string as host:port pair
+ (multiple entries are separated with commas) which acts
+ as the central registry for volumes
+ type: string
+ tenant:
+ description: tenant owning the given Quobyte volume in the
+ Backend Used with dynamically provisioned Quobyte volumes,
+ value is set by the plugin
+ type: string
+ user:
+ description: user to map volume access to Defaults to serivceaccount
+ user
+ type: string
+ volume:
+ description: volume is a string that references an already
+ created Quobyte volume by name.
+ type: string
+ required:
+ - registry
+ - volume
+ type: object
+ rbd:
+ description: 'rbd represents a Rados Block Device mount on the
+ host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md'
+ properties:
+ fsType:
+ description: 'fsType is the filesystem type of the volume
+ that you want to mount. Tip: Ensure that the filesystem
+ type is supported by the host operating system. Examples:
+ "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd
+ TODO: how do we prevent errors in the filesystem from
+ compromising the machine'
+ type: string
+ image:
+ description: 'image is the rados image name. More info:
+ https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: string
+ keyring:
+ description: 'keyring is the path to key ring for RBDUser.
+ Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: string
+ monitors:
+ description: 'monitors is a collection of Ceph monitors.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ items:
+ type: string
+ type: array
+ pool:
+ description: 'pool is the rados pool name. Default is rbd.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: string
+ readOnly:
+ description: 'readOnly here will force the ReadOnly setting
+ in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: boolean
+ secretRef:
+ description: 'secretRef is name of the authentication secret
+ for RBDUser. If provided overrides keyring. Default is
+ nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ user:
+ description: 'user is the rados user name. Default is admin.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: string
+ required:
+ - image
+ - monitors
+ type: object
+ scaleIO:
+ description: scaleIO represents a ScaleIO persistent volume
+ attached and mounted on Kubernetes nodes.
+ properties:
+ fsType:
+ description: fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Default is "xfs".
+ type: string
+ gateway:
+ description: gateway is the host address of the ScaleIO
+ API Gateway.
+ type: string
+ protectionDomain:
+ description: protectionDomain is the name of the ScaleIO
+ Protection Domain for the configured storage.
+ type: string
+ readOnly:
+ description: readOnly Defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretRef:
+ description: secretRef references to the secret for ScaleIO
+ user and other sensitive information. If this is not provided,
+ Login operation will fail.
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ sslEnabled:
+ description: sslEnabled Flag enable/disable SSL communication
+ with Gateway, default false
+ type: boolean
+ storageMode:
+ description: storageMode indicates whether the storage for
+ a volume should be ThickProvisioned or ThinProvisioned.
+ Default is ThinProvisioned.
+ type: string
+ storagePool:
+ description: storagePool is the ScaleIO Storage Pool associated
+ with the protection domain.
+ type: string
+ system:
+ description: system is the name of the storage system as
+ configured in ScaleIO.
+ type: string
+ volumeName:
+ description: volumeName is the name of a volume already
+ created in the ScaleIO system that is associated with
+ this volume source.
+ type: string
+ required:
+ - gateway
+ - secretRef
+ - system
+ type: object
+ secret:
+ description: 'secret represents a secret that should populate
+ this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
+ properties:
+ defaultMode:
+ description: 'defaultMode is Optional: mode bits used to
+ set permissions on created files by default. Must be an
+ octal value between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. Defaults to
+ 0644. Directories within the path are not affected by
+ this setting. This might be in conflict with other options
+ that affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ items:
+ description: items If unspecified, each key-value pair in
+ the Data field of the referenced Secret will be projected
+ into the volume as a file whose name is the key and content
+ is the value. If specified, the listed keys will be projected
+ into the specified paths, and unlisted keys will not be
+ present. If a key is specified which is not present in
+ the Secret, the volume setup will error unless it is marked
+ optional. Paths must be relative and may not contain the
+ '..' path or start with '..'.
+ items:
+ description: Maps a string key to a path within a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: 'mode is Optional: mode bits used to
+ set permissions on this file. Must be an octal value
+ between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. If not
+ specified, the volume defaultMode will be used.
+ This might be in conflict with other options that
+ affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: path is the relative path of the file
+ to map the key to. May not be an absolute path.
+ May not contain the path element '..'. May not start
+ with the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ optional:
+ description: optional field specify whether the Secret or
+ its keys must be defined
+ type: boolean
+ secretName:
+ description: 'secretName is the name of the secret in the
+ pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
+ type: string
+ type: object
+ storageos:
+ description: storageOS represents a StorageOS volume attached
+ and mounted on Kubernetes nodes.
+ properties:
+ fsType:
+ description: fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ readOnly:
+ description: readOnly defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretRef:
+ description: secretRef specifies the secret to use for obtaining
+ the StorageOS API credentials. If not specified, default
+ values will be attempted.
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ volumeName:
+ description: volumeName is the human-readable name of the
+ StorageOS volume. Volume names are only unique within
+ a namespace.
+ type: string
+ volumeNamespace:
+ description: volumeNamespace specifies the scope of the
+ volume within StorageOS. If no namespace is specified
+ then the Pod's namespace will be used. This allows the
+ Kubernetes name scoping to be mirrored within StorageOS
+ for tighter integration. Set VolumeName to any name to
+ override the default behaviour. Set to "default" if you
+ are not using namespaces within StorageOS. Namespaces
+ that do not pre-exist within StorageOS will be created.
+ type: string
+ type: object
+ vsphereVolume:
+ description: vsphereVolume represents a vSphere volume attached
+ and mounted on kubelets host machine
+ properties:
+ fsType:
+ description: fsType is filesystem type to mount. Must be
+ a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ storagePolicyID:
+ description: storagePolicyID is the storage Policy Based
+ Management (SPBM) profile ID associated with the StoragePolicyName.
+ type: string
+ storagePolicyName:
+ description: storagePolicyName is the storage Policy Based
+ Management (SPBM) profile name.
+ type: string
+ volumePath:
+ description: volumePath is the path that identifies vSphere
+ volume vmdk
+ type: string
+ required:
+ - volumePath
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ web:
+ description: Defines the web command line flags when starting Alertmanager.
+ properties:
+ httpConfig:
+ description: Defines HTTP parameters for web server.
+ properties:
+ headers:
+ description: List of headers that can be added to HTTP responses.
+ properties:
+ contentSecurityPolicy:
+ description: Set the Content-Security-Policy header to
+ HTTP responses. Unset if blank.
+ type: string
+ strictTransportSecurity:
+ description: Set the Strict-Transport-Security header
+ to HTTP responses. Unset if blank. Please make sure
+ that you use this with care as this header might force
+ browsers to load Prometheus and the other applications
+ hosted on the same domain and subdomains over HTTPS.
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
+ type: string
+ xContentTypeOptions:
+ description: Set the X-Content-Type-Options header to
+ HTTP responses. Unset if blank. Accepted value is nosniff.
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
+ enum:
+ - ""
+ - NoSniff
+ type: string
+ xFrameOptions:
+ description: Set the X-Frame-Options header to HTTP responses.
+ Unset if blank. Accepted values are deny and sameorigin.
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
+ enum:
+ - ""
+ - Deny
+ - SameOrigin
+ type: string
+ xXSSProtection:
+ description: Set the X-XSS-Protection header to all responses.
+ Unset if blank. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
+ type: string
+ type: object
+ http2:
+ description: Enable HTTP/2 support. Note that HTTP/2 is only
+ supported with TLS. When TLSConfig is not configured, HTTP/2
+ will be disabled. Whenever the value of the field changes,
+ a rolling update will be triggered.
+ type: boolean
+ type: object
+ tlsConfig:
+ description: Defines the TLS parameters for HTTPS.
+ properties:
+ cert:
+ description: Contains the TLS certificate for the server.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cipherSuites:
+ description: 'List of supported cipher suites for TLS versions
+ up to TLS 1.2. If empty, Go default cipher suites are used.
+ Available cipher suites are documented in the go documentation:
+ https://golang.org/pkg/crypto/tls/#pkg-constants'
+ items:
+ type: string
+ type: array
+ client_ca:
+ description: Contains the CA certificate for client certificate
+ authentication to the server.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientAuthType:
+ description: 'Server policy for client authentication. Maps
+ to ClientAuth Policies. For more detail on clientAuth options:
+ https://golang.org/pkg/crypto/tls/#ClientAuthType'
+ type: string
+ curvePreferences:
+ description: 'Elliptic curves that will be used in an ECDHE
+ handshake, in preference order. Available curves are documented
+ in the go documentation: https://golang.org/pkg/crypto/tls/#CurveID'
+ items:
+ type: string
+ type: array
+ keySecret:
+ description: Secret containing the TLS key for the server.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ maxVersion:
+ description: Maximum TLS version that is acceptable. Defaults
+ to TLS13.
+ type: string
+ minVersion:
+ description: Minimum TLS version that is acceptable. Defaults
+ to TLS12.
+ type: string
+ preferServerCipherSuites:
+ description: Controls whether the server selects the client's
+ most preferred cipher suite, or the server's most preferred
+ cipher suite. If true then the server's preference, as expressed
+ in the order of elements in cipherSuites, is used.
+ type: boolean
+ required:
+ - cert
+ - keySecret
+ type: object
+ type: object
+ type: object
+ status:
+ description: 'Most recent observed status of the Alertmanager cluster.
+ Read-only. Not included when requesting from the apiserver, only from
+ the Prometheus Operator API itself. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status'
+ properties:
+ availableReplicas:
+ description: Total number of available pods (ready for at least minReadySeconds)
+ targeted by this Alertmanager cluster.
+ format: int32
+ type: integer
+ paused:
+ description: Represents whether any actions on the underlying managed
+ objects are being performed. Only delete actions will be performed.
+ type: boolean
+ replicas:
+ description: Total number of non-terminated pods targeted by this
+ Alertmanager cluster (their labels match the selector).
+ format: int32
+ type: integer
+ unavailableReplicas:
+ description: Total number of unavailable pods targeted by this Alertmanager
+ cluster.
+ format: int32
+ type: integer
+ updatedReplicas:
+ description: Total number of non-terminated pods targeted by this
+ Alertmanager cluster that have the desired version spec.
+ format: int32
+ type: integer
+ required:
+ - availableReplicas
+ - paused
+ - replicas
+ - unavailableReplicas
+ - updatedReplicas
+ type: object
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
+ subresources: {}
diff --git a/kube-prometheus-stack/crds/crd-podmonitors.yaml b/kube-prometheus-stack/crds/crd-podmonitors.yaml
new file mode 100644
index 00000000..e1de8d8e
--- /dev/null
+++ b/kube-prometheus-stack/crds/crd-podmonitors.yaml
@@ -0,0 +1,663 @@
+# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.2/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.9.2
+ creationTimestamp: null
+ name: podmonitors.monitoring.coreos.com
+spec:
+ group: monitoring.coreos.com
+ names:
+ categories:
+ - prometheus-operator
+ kind: PodMonitor
+ listKind: PodMonitorList
+ plural: podmonitors
+ shortNames:
+ - pmon
+ singular: podmonitor
+ scope: Namespaced
+ versions:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description: PodMonitor defines monitoring for a set of pods.
+ 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: Specification of desired Pod selection for target discovery
+ by Prometheus.
+ properties:
+ attachMetadata:
+ description: 'Attaches node metadata to discovered targets. Only valid
+ for role: pod. Only valid in Prometheus versions 2.35.0 and newer.'
+ properties:
+ node:
+ description: When set to true, Prometheus must have permissions
+ to get Nodes.
+ type: boolean
+ type: object
+ jobLabel:
+ description: The label to use to retrieve the job name from.
+ type: string
+ labelLimit:
+ description: Per-scrape limit on number of labels that will be accepted
+ for a sample. Only valid in Prometheus versions 2.27.0 and newer.
+ format: int64
+ type: integer
+ labelNameLengthLimit:
+ description: Per-scrape limit on length of labels name that will be
+ accepted for a sample. Only valid in Prometheus versions 2.27.0
+ and newer.
+ format: int64
+ type: integer
+ labelValueLengthLimit:
+ description: Per-scrape limit on length of labels value that will
+ be accepted for a sample. Only valid in Prometheus versions 2.27.0
+ and newer.
+ format: int64
+ type: integer
+ namespaceSelector:
+ description: Selector to select which namespaces the Endpoints objects
+ are discovered from.
+ properties:
+ any:
+ description: Boolean describing whether all namespaces are selected
+ in contrast to a list restricting them.
+ type: boolean
+ matchNames:
+ description: List of namespace names to select from.
+ items:
+ type: string
+ type: array
+ type: object
+ podMetricsEndpoints:
+ description: A list of endpoints allowed as part of this PodMonitor.
+ items:
+ description: PodMetricsEndpoint defines a scrapeable endpoint of
+ a Kubernetes Pod serving Prometheus metrics.
+ properties:
+ authorization:
+ description: Authorization section for this endpoint
+ properties:
+ credentials:
+ description: The secret's key that contains the credentials
+ of the request
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults to Bearer,
+ Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: 'BasicAuth allow an endpoint to authenticate over
+ basic authentication. More info: https://prometheus.io/docs/operating/configuration/#endpoint'
+ properties:
+ password:
+ description: The secret in the service monitor namespace
+ that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor namespace
+ that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenSecret:
+ description: Secret to mount to read bearer token for scraping
+ targets. The secret needs to be in the same namespace as the
+ pod monitor and accessible by the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ enableHttp2:
+ description: Whether to enable HTTP2.
+ type: boolean
+ followRedirects:
+ description: FollowRedirects configures whether scrape requests
+ follow HTTP 3xx redirects.
+ type: boolean
+ honorLabels:
+ description: HonorLabels chooses the metric's labels on collisions
+ with target labels.
+ type: boolean
+ honorTimestamps:
+ description: HonorTimestamps controls whether Prometheus respects
+ the timestamps present in scraped data.
+ type: boolean
+ interval:
+ description: Interval at which metrics should be scraped If
+ not specified Prometheus' global scrape interval is used.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ metricRelabelings:
+ description: MetricRelabelConfigs to apply to samples before
+ ingestion.
+ items:
+ description: 'RelabelConfig allows dynamic rewriting of the
+ label set, being applied to samples before ingestion. It
+ defines ``-section of Prometheus
+ configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
+ properties:
+ action:
+ default: replace
+ description: Action to perform based on regex matching.
+ Default is 'replace'. uppercase and lowercase actions
+ require Prometheus >= 2.36.
+ enum:
+ - replace
+ - Replace
+ - keep
+ - Keep
+ - drop
+ - Drop
+ - hashmod
+ - HashMod
+ - labelmap
+ - LabelMap
+ - labeldrop
+ - LabelDrop
+ - labelkeep
+ - LabelKeep
+ - lowercase
+ - Lowercase
+ - uppercase
+ - Uppercase
+ type: string
+ modulus:
+ description: Modulus to take of the hash of the source
+ label values.
+ format: int64
+ type: integer
+ regex:
+ description: Regular expression against which the extracted
+ value is matched. Default is '(.*)'
+ type: string
+ replacement:
+ description: Replacement value against which a regex replace
+ is performed if the regular expression matches. Regex
+ capture groups are available. Default is '$1'
+ type: string
+ separator:
+ description: Separator placed between concatenated source
+ label values. default is ';'.
+ type: string
+ sourceLabels:
+ description: The source labels select values from existing
+ labels. Their content is concatenated using the configured
+ separator and matched against the configured regular
+ expression for the replace, keep, and drop actions.
+ items:
+ description: LabelName is a valid Prometheus label name
+ which may only contain ASCII letters, numbers, as
+ well as underscores.
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ type: string
+ type: array
+ targetLabel:
+ description: Label to which the resulting value is written
+ in a replace action. It is mandatory for replace actions.
+ Regex capture groups are available.
+ type: string
+ type: object
+ type: array
+ oauth2:
+ description: OAuth2 for the URL. Only valid in Prometheus versions
+ 2.27.0 and newer.
+ properties:
+ clientId:
+ description: The secret or configmap containing the OAuth2
+ client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2 client secret
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ params:
+ additionalProperties:
+ items:
+ type: string
+ type: array
+ description: Optional HTTP URL parameters
+ type: object
+ path:
+ description: HTTP path to scrape for metrics. If empty, Prometheus
+ uses the default value (e.g. `/metrics`).
+ type: string
+ port:
+ description: Name of the pod port this endpoint refers to. Mutually
+ exclusive with targetPort.
+ type: string
+ proxyUrl:
+ description: ProxyURL eg http://proxyserver:2195 Directs scrapes
+ to proxy through this endpoint.
+ type: string
+ relabelings:
+ description: 'RelabelConfigs to apply to samples before scraping.
+ Prometheus Operator automatically adds relabelings for a few
+ standard Kubernetes fields. The original scrape job''s name
+ is available via the `__tmp_prometheus_job_name` label. More
+ info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config'
+ items:
+ description: 'RelabelConfig allows dynamic rewriting of the
+ label set, being applied to samples before ingestion. It
+ defines ``-section of Prometheus
+ configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
+ properties:
+ action:
+ default: replace
+ description: Action to perform based on regex matching.
+ Default is 'replace'. uppercase and lowercase actions
+ require Prometheus >= 2.36.
+ enum:
+ - replace
+ - Replace
+ - keep
+ - Keep
+ - drop
+ - Drop
+ - hashmod
+ - HashMod
+ - labelmap
+ - LabelMap
+ - labeldrop
+ - LabelDrop
+ - labelkeep
+ - LabelKeep
+ - lowercase
+ - Lowercase
+ - uppercase
+ - Uppercase
+ type: string
+ modulus:
+ description: Modulus to take of the hash of the source
+ label values.
+ format: int64
+ type: integer
+ regex:
+ description: Regular expression against which the extracted
+ value is matched. Default is '(.*)'
+ type: string
+ replacement:
+ description: Replacement value against which a regex replace
+ is performed if the regular expression matches. Regex
+ capture groups are available. Default is '$1'
+ type: string
+ separator:
+ description: Separator placed between concatenated source
+ label values. default is ';'.
+ type: string
+ sourceLabels:
+ description: The source labels select values from existing
+ labels. Their content is concatenated using the configured
+ separator and matched against the configured regular
+ expression for the replace, keep, and drop actions.
+ items:
+ description: LabelName is a valid Prometheus label name
+ which may only contain ASCII letters, numbers, as
+ well as underscores.
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ type: string
+ type: array
+ targetLabel:
+ description: Label to which the resulting value is written
+ in a replace action. It is mandatory for replace actions.
+ Regex capture groups are available.
+ type: string
+ type: object
+ type: array
+ scheme:
+ description: HTTP scheme to use for scraping.
+ type: string
+ scrapeTimeout:
+ description: Timeout after which the scrape is ended If not
+ specified, the Prometheus global scrape interval is used.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ targetPort:
+ anyOf:
+ - type: integer
+ - type: string
+ description: 'Deprecated: Use ''port'' instead.'
+ x-kubernetes-int-or-string: true
+ tlsConfig:
+ description: TLS configuration to use when scraping the endpoint.
+ properties:
+ ca:
+ description: Struct containing the CA cert to use for the
+ targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert file for
+ the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key file for the
+ targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the targets.
+ type: string
+ type: object
+ type: object
+ type: array
+ podTargetLabels:
+ description: PodTargetLabels transfers labels on the Kubernetes Pod
+ onto the target.
+ items:
+ type: string
+ type: array
+ sampleLimit:
+ description: SampleLimit defines per-scrape limit on number of scraped
+ samples that will be accepted.
+ format: int64
+ type: integer
+ selector:
+ description: Selector to select Pod 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
+ x-kubernetes-map-type: atomic
+ targetLimit:
+ description: TargetLimit defines a limit on the number of scraped
+ targets that will be accepted.
+ format: int64
+ type: integer
+ required:
+ - podMetricsEndpoints
+ - selector
+ type: object
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
diff --git a/kube-prometheus-stack/crds/crd-probes.yaml b/kube-prometheus-stack/crds/crd-probes.yaml
new file mode 100644
index 00000000..eaaba48e
--- /dev/null
+++ b/kube-prometheus-stack/crds/crd-probes.yaml
@@ -0,0 +1,704 @@
+# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.2/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.9.2
+ creationTimestamp: null
+ name: probes.monitoring.coreos.com
+spec:
+ group: monitoring.coreos.com
+ names:
+ categories:
+ - prometheus-operator
+ kind: Probe
+ listKind: ProbeList
+ plural: probes
+ shortNames:
+ - prb
+ singular: probe
+ scope: Namespaced
+ versions:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description: Probe defines monitoring for a set of static targets or ingresses.
+ 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: Specification of desired Ingress selection for target discovery
+ by Prometheus.
+ properties:
+ authorization:
+ description: Authorization section for this endpoint
+ properties:
+ credentials:
+ description: The secret's key that contains the credentials of
+ the request
+ properties:
+ key:
+ description: The key of the secret to select from. Must be
+ a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be
+ defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults to Bearer,
+ Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: 'BasicAuth allow an endpoint to authenticate over basic
+ authentication. More info: https://prometheus.io/docs/operating/configuration/#endpoint'
+ properties:
+ password:
+ description: The secret in the service monitor namespace that
+ contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must be
+ a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be
+ defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor namespace that
+ contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must be
+ a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be
+ defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenSecret:
+ description: Secret to mount to read bearer token for scraping targets.
+ The secret needs to be in the same namespace as the probe and accessible
+ by the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must be a
+ valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ interval:
+ description: Interval at which targets are probed using the configured
+ prober. If not specified Prometheus' global scrape interval is used.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ jobName:
+ description: The job name assigned to scraped metrics by default.
+ type: string
+ labelLimit:
+ description: Per-scrape limit on number of labels that will be accepted
+ for a sample. Only valid in Prometheus versions 2.27.0 and newer.
+ format: int64
+ type: integer
+ labelNameLengthLimit:
+ description: Per-scrape limit on length of labels name that will be
+ accepted for a sample. Only valid in Prometheus versions 2.27.0
+ and newer.
+ format: int64
+ type: integer
+ labelValueLengthLimit:
+ description: Per-scrape limit on length of labels value that will
+ be accepted for a sample. Only valid in Prometheus versions 2.27.0
+ and newer.
+ format: int64
+ type: integer
+ metricRelabelings:
+ description: MetricRelabelConfigs to apply to samples before ingestion.
+ items:
+ description: 'RelabelConfig allows dynamic rewriting of the label
+ set, being applied to samples before ingestion. It defines ``-section
+ of Prometheus configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
+ properties:
+ action:
+ default: replace
+ description: Action to perform based on regex matching. Default
+ is 'replace'. uppercase and lowercase actions require Prometheus
+ >= 2.36.
+ enum:
+ - replace
+ - Replace
+ - keep
+ - Keep
+ - drop
+ - Drop
+ - hashmod
+ - HashMod
+ - labelmap
+ - LabelMap
+ - labeldrop
+ - LabelDrop
+ - labelkeep
+ - LabelKeep
+ - lowercase
+ - Lowercase
+ - uppercase
+ - Uppercase
+ type: string
+ modulus:
+ description: Modulus to take of the hash of the source label
+ values.
+ format: int64
+ type: integer
+ regex:
+ description: Regular expression against which the extracted
+ value is matched. Default is '(.*)'
+ type: string
+ replacement:
+ description: Replacement value against which a regex replace
+ is performed if the regular expression matches. Regex capture
+ groups are available. Default is '$1'
+ type: string
+ separator:
+ description: Separator placed between concatenated source label
+ values. default is ';'.
+ type: string
+ sourceLabels:
+ description: The source labels select values from existing labels.
+ Their content is concatenated using the configured separator
+ and matched against the configured regular expression for
+ the replace, keep, and drop actions.
+ items:
+ description: LabelName is a valid Prometheus label name which
+ may only contain ASCII letters, numbers, as well as underscores.
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ type: string
+ type: array
+ targetLabel:
+ description: Label to which the resulting value is written in
+ a replace action. It is mandatory for replace actions. Regex
+ capture groups are available.
+ type: string
+ type: object
+ type: array
+ module:
+ description: 'The module to use for probing specifying how to probe
+ the target. Example module configuring in the blackbox exporter:
+ https://github.com/prometheus/blackbox_exporter/blob/master/example.yml'
+ type: string
+ oauth2:
+ description: OAuth2 for the URL. Only valid in Prometheus versions
+ 2.27.0 and newer.
+ properties:
+ clientId:
+ description: The secret or configmap containing the OAuth2 client
+ id
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2 client secret
+ properties:
+ key:
+ description: The key of the secret to select from. Must be
+ a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be
+ defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ prober:
+ description: Specification for the prober to use for probing targets.
+ The prober.URL parameter is required. Targets cannot be probed if
+ left empty.
+ properties:
+ path:
+ default: /probe
+ description: Path to collect metrics from. Defaults to `/probe`.
+ type: string
+ proxyUrl:
+ description: Optional ProxyURL.
+ type: string
+ scheme:
+ description: HTTP scheme to use for scraping. Defaults to `http`.
+ type: string
+ url:
+ description: Mandatory URL of the prober.
+ type: string
+ required:
+ - url
+ type: object
+ sampleLimit:
+ description: SampleLimit defines per-scrape limit on number of scraped
+ samples that will be accepted.
+ format: int64
+ type: integer
+ scrapeTimeout:
+ description: Timeout for scraping metrics from the Prometheus exporter.
+ If not specified, the Prometheus global scrape interval is used.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ targetLimit:
+ description: TargetLimit defines a limit on the number of scraped
+ targets that will be accepted.
+ format: int64
+ type: integer
+ targets:
+ description: Targets defines a set of static or dynamically discovered
+ targets to probe.
+ properties:
+ ingress:
+ description: ingress defines the Ingress objects to probe and
+ the relabeling configuration. If `staticConfig` is also defined,
+ `staticConfig` takes precedence.
+ properties:
+ namespaceSelector:
+ description: From which namespaces to select Ingress objects.
+ properties:
+ any:
+ description: Boolean describing whether all namespaces
+ are selected in contrast to a list restricting them.
+ type: boolean
+ matchNames:
+ description: List of namespace names to select from.
+ items:
+ type: string
+ type: array
+ type: object
+ relabelingConfigs:
+ description: 'RelabelConfigs to apply to the label set of
+ the target before it gets scraped. The original ingress
+ address is available via the `__tmp_prometheus_ingress_address`
+ label. It can be used to customize the probed URL. The original
+ scrape job''s name is available via the `__tmp_prometheus_job_name`
+ label. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config'
+ items:
+ description: 'RelabelConfig allows dynamic rewriting of
+ the label set, being applied to samples before ingestion.
+ It defines ``-section of Prometheus
+ configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
+ properties:
+ action:
+ default: replace
+ description: Action to perform based on regex matching.
+ Default is 'replace'. uppercase and lowercase actions
+ require Prometheus >= 2.36.
+ enum:
+ - replace
+ - Replace
+ - keep
+ - Keep
+ - drop
+ - Drop
+ - hashmod
+ - HashMod
+ - labelmap
+ - LabelMap
+ - labeldrop
+ - LabelDrop
+ - labelkeep
+ - LabelKeep
+ - lowercase
+ - Lowercase
+ - uppercase
+ - Uppercase
+ type: string
+ modulus:
+ description: Modulus to take of the hash of the source
+ label values.
+ format: int64
+ type: integer
+ regex:
+ description: Regular expression against which the extracted
+ value is matched. Default is '(.*)'
+ type: string
+ replacement:
+ description: Replacement value against which a regex
+ replace is performed if the regular expression matches.
+ Regex capture groups are available. Default is '$1'
+ type: string
+ separator:
+ description: Separator placed between concatenated source
+ label values. default is ';'.
+ type: string
+ sourceLabels:
+ description: The source labels select values from existing
+ labels. Their content is concatenated using the configured
+ separator and matched against the configured regular
+ expression for the replace, keep, and drop actions.
+ items:
+ description: LabelName is a valid Prometheus label
+ name which may only contain ASCII letters, numbers,
+ as well as underscores.
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ type: string
+ type: array
+ targetLabel:
+ description: Label to which the resulting value is written
+ in a replace action. It is mandatory for replace actions.
+ Regex capture groups are available.
+ type: string
+ type: object
+ type: array
+ selector:
+ description: Selector to select the Ingress 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
+ x-kubernetes-map-type: atomic
+ type: object
+ staticConfig:
+ description: 'staticConfig defines the static list of targets
+ to probe and the relabeling configuration. If `ingress` is also
+ defined, `staticConfig` takes precedence. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#static_config.'
+ properties:
+ labels:
+ additionalProperties:
+ type: string
+ description: Labels assigned to all metrics scraped from the
+ targets.
+ type: object
+ relabelingConfigs:
+ description: 'RelabelConfigs to apply to the label set of
+ the targets before it gets scraped. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config'
+ items:
+ description: 'RelabelConfig allows dynamic rewriting of
+ the label set, being applied to samples before ingestion.
+ It defines ``-section of Prometheus
+ configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
+ properties:
+ action:
+ default: replace
+ description: Action to perform based on regex matching.
+ Default is 'replace'. uppercase and lowercase actions
+ require Prometheus >= 2.36.
+ enum:
+ - replace
+ - Replace
+ - keep
+ - Keep
+ - drop
+ - Drop
+ - hashmod
+ - HashMod
+ - labelmap
+ - LabelMap
+ - labeldrop
+ - LabelDrop
+ - labelkeep
+ - LabelKeep
+ - lowercase
+ - Lowercase
+ - uppercase
+ - Uppercase
+ type: string
+ modulus:
+ description: Modulus to take of the hash of the source
+ label values.
+ format: int64
+ type: integer
+ regex:
+ description: Regular expression against which the extracted
+ value is matched. Default is '(.*)'
+ type: string
+ replacement:
+ description: Replacement value against which a regex
+ replace is performed if the regular expression matches.
+ Regex capture groups are available. Default is '$1'
+ type: string
+ separator:
+ description: Separator placed between concatenated source
+ label values. default is ';'.
+ type: string
+ sourceLabels:
+ description: The source labels select values from existing
+ labels. Their content is concatenated using the configured
+ separator and matched against the configured regular
+ expression for the replace, keep, and drop actions.
+ items:
+ description: LabelName is a valid Prometheus label
+ name which may only contain ASCII letters, numbers,
+ as well as underscores.
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ type: string
+ type: array
+ targetLabel:
+ description: Label to which the resulting value is written
+ in a replace action. It is mandatory for replace actions.
+ Regex capture groups are available.
+ type: string
+ type: object
+ type: array
+ static:
+ description: The list of hosts to probe.
+ items:
+ type: string
+ type: array
+ type: object
+ type: object
+ tlsConfig:
+ description: TLS configuration to use when scraping the endpoint.
+ properties:
+ ca:
+ description: Struct containing the CA cert to use for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cert:
+ description: Struct containing the client cert file for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keySecret:
+ description: Secret containing the client key file for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must be
+ a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be
+ defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the targets.
+ type: string
+ type: object
+ type: object
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
diff --git a/kube-prometheus-stack/crds/crd-prometheuses.yaml b/kube-prometheus-stack/crds/crd-prometheuses.yaml
new file mode 100644
index 00000000..69debc2e
--- /dev/null
+++ b/kube-prometheus-stack/crds/crd-prometheuses.yaml
@@ -0,0 +1,8801 @@
+# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.2/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.9.2
+ creationTimestamp: null
+ name: prometheuses.monitoring.coreos.com
+spec:
+ group: monitoring.coreos.com
+ names:
+ categories:
+ - prometheus-operator
+ kind: Prometheus
+ listKind: PrometheusList
+ plural: prometheuses
+ shortNames:
+ - prom
+ singular: prometheus
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - description: The version of Prometheus
+ jsonPath: .spec.version
+ name: Version
+ type: string
+ - description: The desired replicas number of Prometheuses
+ jsonPath: .spec.replicas
+ name: Replicas
+ type: integer
+ - jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1
+ schema:
+ openAPIV3Schema:
+ description: Prometheus defines a Prometheus deployment.
+ 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: 'Specification of the desired behavior of the Prometheus
+ cluster. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status'
+ properties:
+ additionalAlertManagerConfigs:
+ description: 'AdditionalAlertManagerConfigs allows specifying a key
+ of a Secret containing additional Prometheus AlertManager configurations.
+ AlertManager configurations specified are appended to the configurations
+ generated by the Prometheus Operator. Job configurations specified
+ must have the form as specified in the official Prometheus documentation:
+ https://prometheus.io/docs/prometheus/latest/configuration/configuration/#alertmanager_config.
+ As AlertManager configs are appended, the user is responsible to
+ make sure it is valid. Note that using this feature may expose the
+ possibility to break upgrades of Prometheus. It is advised to review
+ Prometheus release notes to ensure that no incompatible AlertManager
+ configs are going to break Prometheus after the upgrade.'
+ properties:
+ key:
+ description: The key of the secret to select from. Must be a
+ valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ additionalAlertRelabelConfigs:
+ description: 'AdditionalAlertRelabelConfigs allows specifying a key
+ of a Secret containing additional Prometheus alert relabel configurations.
+ Alert relabel configurations specified are appended to the configurations
+ generated by the Prometheus Operator. Alert relabel configurations
+ specified must have the form as specified in the official Prometheus
+ documentation: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#alert_relabel_configs.
+ As alert relabel configs are appended, the user is responsible to
+ make sure it is valid. Note that using this feature may expose the
+ possibility to break upgrades of Prometheus. It is advised to review
+ Prometheus release notes to ensure that no incompatible alert relabel
+ configs are going to break Prometheus after the upgrade.'
+ properties:
+ key:
+ description: The key of the secret to select from. Must be a
+ valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ additionalArgs:
+ description: AdditionalArgs allows setting additional arguments for
+ the Prometheus container. It is intended for e.g. activating hidden
+ flags which are not supported by the dedicated configuration options
+ yet. The arguments are passed as-is to the Prometheus container
+ which may cause issues if they are invalid or not supporeted by
+ the given Prometheus version. In case of an argument conflict (e.g.
+ an argument which is already set by the operator itself) or when
+ providing an invalid argument the reconciliation will fail and an
+ error will be logged.
+ items:
+ description: Argument as part of the AdditionalArgs list.
+ properties:
+ name:
+ description: Name of the argument, e.g. "scrape.discovery-reload-interval".
+ minLength: 1
+ type: string
+ value:
+ description: Argument value, e.g. 30s. Can be empty for name-only
+ arguments (e.g. --storage.tsdb.no-lockfile)
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ additionalScrapeConfigs:
+ description: 'AdditionalScrapeConfigs allows specifying a key of a
+ Secret containing additional Prometheus scrape configurations. Scrape
+ configurations specified are appended to the configurations generated
+ by the Prometheus Operator. Job configurations specified must have
+ the form as specified in the official Prometheus documentation:
+ https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config.
+ As scrape configs are appended, the user is responsible to make
+ sure it is valid. Note that using this feature may expose the possibility
+ to break upgrades of Prometheus. It is advised to review Prometheus
+ release notes to ensure that no incompatible scrape configs are
+ going to break Prometheus after the upgrade.'
+ properties:
+ key:
+ description: The key of the secret to select from. Must be a
+ valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ affinity:
+ description: If specified, the pod's scheduling constraints.
+ properties:
+ nodeAffinity:
+ description: Describes node affinity scheduling rules for the
+ pod.
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: The scheduler will prefer to schedule pods to
+ nodes that satisfy the affinity expressions specified by
+ this field, but it may choose a node that violates one or
+ more of the expressions. The node that is most preferred
+ is the one with the greatest sum of weights, i.e. for each
+ node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions,
+ etc.), compute a sum by iterating through the elements of
+ this field and adding "weight" to the sum if the node matches
+ the corresponding matchExpressions; the node(s) with the
+ highest sum are the most preferred.
+ items:
+ description: An empty preferred scheduling term matches
+ all objects with implicit weight 0 (i.e. it's a no-op).
+ A null preferred scheduling term matches no objects (i.e.
+ is also a no-op).
+ properties:
+ preference:
+ description: A node selector term, associated with the
+ corresponding weight.
+ properties:
+ matchExpressions:
+ description: A list of node selector requirements
+ by node's labels.
+ items:
+ description: A node selector requirement is a
+ selector that contains values, a key, and an
+ operator that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: Represents a key's relationship
+ to a set of values. Valid operators are
+ In, NotIn, Exists, DoesNotExist. Gt, and
+ Lt.
+ type: string
+ values:
+ description: 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. If the operator is Gt or
+ Lt, the values array must have a single
+ element, which will be interpreted as an
+ integer. This array is replaced during a
+ strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchFields:
+ description: A list of node selector requirements
+ by node's fields.
+ items:
+ description: A node selector requirement is a
+ selector that contains values, a key, and an
+ operator that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: Represents a key's relationship
+ to a set of values. Valid operators are
+ In, NotIn, Exists, DoesNotExist. Gt, and
+ Lt.
+ type: string
+ values:
+ description: 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. If the operator is Gt or
+ Lt, the values array must have a single
+ element, which will be interpreted as an
+ integer. This array is replaced during a
+ strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ type: object
+ x-kubernetes-map-type: atomic
+ weight:
+ description: Weight associated with matching the corresponding
+ nodeSelectorTerm, in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - preference
+ - weight
+ type: object
+ type: array
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: If the affinity requirements specified by this
+ field are not met at scheduling time, the pod will not be
+ scheduled onto the node. If the affinity requirements specified
+ by this field cease to be met at some point during pod execution
+ (e.g. due to an update), the system may or may not try to
+ eventually evict the pod from its node.
+ properties:
+ nodeSelectorTerms:
+ description: Required. A list of node selector terms.
+ The terms are ORed.
+ items:
+ description: A null or empty node selector term matches
+ no objects. The requirements of them are ANDed. The
+ TopologySelectorTerm type implements a subset of the
+ NodeSelectorTerm.
+ properties:
+ matchExpressions:
+ description: A list of node selector requirements
+ by node's labels.
+ items:
+ description: A node selector requirement is a
+ selector that contains values, a key, and an
+ operator that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: Represents a key's relationship
+ to a set of values. Valid operators are
+ In, NotIn, Exists, DoesNotExist. Gt, and
+ Lt.
+ type: string
+ values:
+ description: 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. If the operator is Gt or
+ Lt, the values array must have a single
+ element, which will be interpreted as an
+ integer. This array is replaced during a
+ strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchFields:
+ description: A list of node selector requirements
+ by node's fields.
+ items:
+ description: A node selector requirement is a
+ selector that contains values, a key, and an
+ operator that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: Represents a key's relationship
+ to a set of values. Valid operators are
+ In, NotIn, Exists, DoesNotExist. Gt, and
+ Lt.
+ type: string
+ values:
+ description: 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. If the operator is Gt or
+ Lt, the values array must have a single
+ element, which will be interpreted as an
+ integer. This array is replaced during a
+ strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ required:
+ - nodeSelectorTerms
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ podAffinity:
+ description: Describes pod affinity scheduling rules (e.g. co-locate
+ this pod in the same node, zone, etc. as some other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: The scheduler will prefer to schedule pods to
+ nodes that satisfy the affinity expressions specified by
+ this field, but it may choose a node that violates one or
+ more of the expressions. The node that is most preferred
+ is the one with the greatest sum of weights, i.e. for each
+ node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions,
+ etc.), compute a sum by iterating through the elements of
+ this field and adding "weight" to the sum if the node has
+ pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched WeightedPodAffinityTerm
+ fields are added per-node to find the most preferred node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term, associated
+ with the corresponding weight.
+ properties:
+ labelSelector:
+ description: A label query over a set of resources,
+ in this case pods.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaceSelector:
+ description: A label query over the set of namespaces
+ that the term applies to. The term is applied
+ to the union of the namespaces selected by this
+ field and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list
+ means "this pod's namespace". An empty selector
+ ({}) matches all namespaces.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: namespaces specifies a static list
+ of namespace names that the term applies to. The
+ term is applied to the union of the namespaces
+ listed in this field and the ones selected by
+ namespaceSelector. null or empty namespaces list
+ and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ topologyKey:
+ description: This pod should be co-located (affinity)
+ or not co-located (anti-affinity) with the pods
+ matching the labelSelector in the specified namespaces,
+ where co-located is defined as running on a node
+ whose value of the label with key topologyKey
+ matches that of any node on which any of the selected
+ pods is running. Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: weight associated with matching the corresponding
+ podAffinityTerm, in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: If the affinity requirements specified by this
+ field are not met at scheduling time, the pod will not be
+ scheduled onto the node. If the affinity requirements specified
+ by this field cease to be met at some point during pod execution
+ (e.g. due to a pod label update), the system may or may
+ not try to eventually evict the pod from its node. When
+ there are multiple elements, the lists of nodes corresponding
+ to each podAffinityTerm are intersected, i.e. all terms
+ must be satisfied.
+ items:
+ description: Defines a set of pods (namely those matching
+ the labelSelector relative to the given namespace(s))
+ that this pod should be co-located (affinity) or not co-located
+ (anti-affinity) with, where co-located is defined as running
+ on a node whose value of the label with key
+ matches that of any node on which a pod of the set of
+ pods is running
+ properties:
+ labelSelector:
+ description: A label query over a set of resources,
+ in this case pods.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaceSelector:
+ description: A label query over the set of namespaces
+ that the term applies to. The term is applied to the
+ union of the namespaces selected by this field and
+ the ones listed in the namespaces field. null selector
+ and null or empty namespaces list means "this pod's
+ namespace". An empty selector ({}) matches all namespaces.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: namespaces specifies a static list of namespace
+ names that the term applies to. The term is applied
+ to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector. null or
+ empty namespaces list and null namespaceSelector means
+ "this pod's namespace".
+ items:
+ type: string
+ type: array
+ topologyKey:
+ description: This pod should be co-located (affinity)
+ or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where
+ co-located is defined as running on a node whose value
+ of the label with key topologyKey matches that of
+ any node on which any of the selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ type: object
+ podAntiAffinity:
+ description: Describes pod anti-affinity scheduling rules (e.g.
+ avoid putting this pod in the same node, zone, etc. as some
+ other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: The scheduler will prefer to schedule pods to
+ nodes that satisfy the anti-affinity expressions specified
+ by this field, but it may choose a node that violates one
+ or more of the expressions. The node that is most preferred
+ is the one with the greatest sum of weights, i.e. for each
+ node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling anti-affinity expressions,
+ etc.), compute a sum by iterating through the elements of
+ this field and adding "weight" to the sum if the node has
+ pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched WeightedPodAffinityTerm
+ fields are added per-node to find the most preferred node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term, associated
+ with the corresponding weight.
+ properties:
+ labelSelector:
+ description: A label query over a set of resources,
+ in this case pods.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaceSelector:
+ description: A label query over the set of namespaces
+ that the term applies to. The term is applied
+ to the union of the namespaces selected by this
+ field and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list
+ means "this pod's namespace". An empty selector
+ ({}) matches all namespaces.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: namespaces specifies a static list
+ of namespace names that the term applies to. The
+ term is applied to the union of the namespaces
+ listed in this field and the ones selected by
+ namespaceSelector. null or empty namespaces list
+ and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ topologyKey:
+ description: This pod should be co-located (affinity)
+ or not co-located (anti-affinity) with the pods
+ matching the labelSelector in the specified namespaces,
+ where co-located is defined as running on a node
+ whose value of the label with key topologyKey
+ matches that of any node on which any of the selected
+ pods is running. Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: weight associated with matching the corresponding
+ podAffinityTerm, in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: If the anti-affinity requirements specified by
+ this field are not met at scheduling time, the pod will
+ not be scheduled onto the node. If the anti-affinity requirements
+ specified by this field cease to be met at some point during
+ pod execution (e.g. due to a pod label update), the system
+ may or may not try to eventually evict the pod from its
+ node. When there are multiple elements, the lists of nodes
+ corresponding to each podAffinityTerm are intersected, i.e.
+ all terms must be satisfied.
+ items:
+ description: Defines a set of pods (namely those matching
+ the labelSelector relative to the given namespace(s))
+ that this pod should be co-located (affinity) or not co-located
+ (anti-affinity) with, where co-located is defined as running
+ on a node whose value of the label with key
+ matches that of any node on which a pod of the set of
+ pods is running
+ properties:
+ labelSelector:
+ description: A label query over a set of resources,
+ in this case pods.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaceSelector:
+ description: A label query over the set of namespaces
+ that the term applies to. The term is applied to the
+ union of the namespaces selected by this field and
+ the ones listed in the namespaces field. null selector
+ and null or empty namespaces list means "this pod's
+ namespace". An empty selector ({}) matches all namespaces.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: namespaces specifies a static list of namespace
+ names that the term applies to. The term is applied
+ to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector. null or
+ empty namespaces list and null namespaceSelector means
+ "this pod's namespace".
+ items:
+ type: string
+ type: array
+ topologyKey:
+ description: This pod should be co-located (affinity)
+ or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where
+ co-located is defined as running on a node whose value
+ of the label with key topologyKey matches that of
+ any node on which any of the selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ type: object
+ type: object
+ alerting:
+ description: Define details regarding alerting.
+ properties:
+ alertmanagers:
+ description: AlertmanagerEndpoints Prometheus should fire alerts
+ against.
+ items:
+ description: AlertmanagerEndpoints defines a selection of a
+ single Endpoints object containing alertmanager IPs to fire
+ alerts against.
+ properties:
+ apiVersion:
+ description: Version of the Alertmanager API that Prometheus
+ uses to send alerts. It can be "v1" or "v2".
+ type: string
+ authorization:
+ description: Authorization section for this alertmanager
+ endpoint
+ properties:
+ credentials:
+ description: The secret's key that contains the credentials
+ of the request
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults to
+ Bearer, Basic will cause an error
+ type: string
+ type: object
+ bearerTokenFile:
+ description: BearerTokenFile to read from filesystem to
+ use when authenticating to Alertmanager.
+ type: string
+ name:
+ description: Name of Endpoints object in Namespace.
+ type: string
+ namespace:
+ description: Namespace of Endpoints object.
+ type: string
+ pathPrefix:
+ description: Prefix for the HTTP path alerts are pushed
+ to.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Port the Alertmanager API is exposed on.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use when firing alerts.
+ type: string
+ timeout:
+ description: Timeout is a per-target Alertmanager timeout
+ when pushing alerts.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ tlsConfig:
+ description: TLS Config to use for alertmanager connection.
+ properties:
+ ca:
+ description: Struct containing the CA cert to use for
+ the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for
+ the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ caFile:
+ description: Path to the CA cert in the Prometheus container
+ to use for the targets.
+ type: string
+ cert:
+ description: Struct containing the client cert file
+ for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for
+ the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
+ kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ certFile:
+ description: Path to the client cert file in the Prometheus
+ container for the targets.
+ type: string
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keyFile:
+ description: Path to the client key file in the Prometheus
+ container for the targets.
+ type: string
+ keySecret:
+ description: Secret containing the client key file for
+ the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the targets.
+ type: string
+ type: object
+ required:
+ - name
+ - namespace
+ - port
+ type: object
+ type: array
+ required:
+ - alertmanagers
+ type: object
+ allowOverlappingBlocks:
+ description: AllowOverlappingBlocks enables vertical compaction and
+ vertical query merge in Prometheus. This is still experimental in
+ Prometheus so it may change in any upcoming release.
+ type: boolean
+ apiserverConfig:
+ description: APIServerConfig allows specifying a host and auth methods
+ to access apiserver. If left empty, Prometheus is assumed to run
+ inside of the cluster and will discover API servers automatically
+ and use the pod's CA certificate and bearer token file at /var/run/secrets/kubernetes.io/serviceaccount/.
+ properties:
+ authorization:
+ description: Authorization section for accessing apiserver
+ properties:
+ credentials:
+ description: The secret's key that contains the credentials
+ of the request
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ credentialsFile:
+ description: File to read a secret from, mutually exclusive
+ with Credentials (from SafeAuthorization)
+ type: string
+ type:
+ description: Set the authentication type. Defaults to Bearer,
+ Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth allow an endpoint to authenticate over
+ basic authentication
+ properties:
+ password:
+ description: The secret in the service monitor namespace that
+ contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor namespace that
+ contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerToken:
+ description: Bearer token for accessing apiserver.
+ type: string
+ bearerTokenFile:
+ description: File to read bearer token for accessing apiserver.
+ type: string
+ host:
+ description: Host of apiserver. A valid string consisting of a
+ hostname or IP followed by an optional port number
+ type: string
+ tlsConfig:
+ description: TLS Config to use for accessing apiserver.
+ properties:
+ ca:
+ description: Struct containing the CA cert to use for the
+ targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ caFile:
+ description: Path to the CA cert in the Prometheus container
+ to use for the targets.
+ type: string
+ cert:
+ description: Struct containing the client cert file for the
+ targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ certFile:
+ description: Path to the client cert file in the Prometheus
+ container for the targets.
+ type: string
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keyFile:
+ description: Path to the client key file in the Prometheus
+ container for the targets.
+ type: string
+ keySecret:
+ description: Secret containing the client key file for the
+ targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the targets.
+ type: string
+ type: object
+ required:
+ - host
+ type: object
+ arbitraryFSAccessThroughSMs:
+ description: ArbitraryFSAccessThroughSMs configures whether configuration
+ based on a service monitor can access arbitrary files on the file
+ system of the Prometheus container e.g. bearer token files.
+ properties:
+ deny:
+ type: boolean
+ type: object
+ baseImage:
+ description: 'Base image to use for a Prometheus deployment. Deprecated:
+ use ''image'' instead'
+ type: string
+ configMaps:
+ description: ConfigMaps is a list of ConfigMaps in the same namespace
+ as the Prometheus object, which shall be mounted into the Prometheus
+ Pods. The ConfigMaps are mounted into /etc/prometheus/configmaps/.
+ items:
+ type: string
+ type: array
+ containers:
+ description: 'Containers allows injecting additional containers or
+ modifying operator generated containers. This can be used to allow
+ adding an authentication proxy to a Prometheus pod or to change
+ the behavior of an operator generated container. Containers described
+ here modify an operator generated container if they share the same
+ name and modifications are done via a strategic merge patch. The
+ current container names are: `prometheus`, `config-reloader`, and
+ `thanos-sidecar`. Overriding containers is entirely outside the
+ scope of what the maintainers will support and by doing so, you
+ accept that this behaviour may break at any time without notice.'
+ items:
+ description: A single application container that you want to run
+ within a pod.
+ properties:
+ args:
+ description: 'Arguments to the entrypoint. The container image''s
+ CMD is used if this is not provided. Variable references $(VAR_NAME)
+ are expanded using the container''s environment. If a variable
+ cannot be resolved, the reference in the input string will
+ be unchanged. Double $$ are reduced to a single $, which allows
+ for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
+ produce the string literal "$(VAR_NAME)". Escaped references
+ will never be expanded, regardless of whether the variable
+ exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
+ items:
+ type: string
+ type: array
+ command:
+ description: 'Entrypoint array. Not executed within a shell.
+ The container image''s ENTRYPOINT is used if this is not provided.
+ Variable references $(VAR_NAME) are expanded using the container''s
+ environment. If a variable cannot be resolved, the reference
+ in the input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME) syntax:
+ i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
+ Escaped references will never be expanded, regardless of whether
+ the variable exists or not. Cannot be updated. More info:
+ https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
+ items:
+ type: string
+ type: array
+ env:
+ description: List of environment variables to set in the container.
+ Cannot be updated.
+ items:
+ description: EnvVar represents an environment variable present
+ in a Container.
+ properties:
+ name:
+ description: Name of the environment variable. Must be
+ a C_IDENTIFIER.
+ type: string
+ value:
+ description: 'Variable references $(VAR_NAME) are expanded
+ using the previously defined environment variables in
+ the container and any service environment variables.
+ If a variable cannot be resolved, the reference in the
+ input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME)
+ syntax: i.e. "$$(VAR_NAME)" will produce the string
+ literal "$(VAR_NAME)". Escaped references will never
+ be expanded, regardless of whether the variable exists
+ or not. Defaults to "".'
+ type: string
+ valueFrom:
+ description: Source for the environment variable's value.
+ Cannot be used if value is not empty.
+ properties:
+ configMapKeyRef:
+ description: Selects a key of a ConfigMap.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ fieldRef:
+ description: 'Selects a field of the pod: supports
+ metadata.name, metadata.namespace, `metadata.labels['''']`,
+ `metadata.annotations['''']`, spec.nodeName,
+ spec.serviceAccountName, status.hostIP, status.podIP,
+ status.podIPs.'
+ properties:
+ apiVersion:
+ description: Version of the schema the FieldPath
+ is written in terms of, defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select in the
+ specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ resourceFieldRef:
+ description: 'Selects a resource of the container:
+ only resources limits and requests (limits.cpu,
+ limits.memory, limits.ephemeral-storage, requests.cpu,
+ requests.memory and requests.ephemeral-storage)
+ are currently supported.'
+ properties:
+ containerName:
+ description: 'Container name: required for volumes,
+ optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format of the
+ exposed resources, defaults to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ secretKeyRef:
+ description: Selects a key of a secret in the pod's
+ namespace
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ envFrom:
+ description: List of sources to populate environment variables
+ in the container. The keys defined within a source must be
+ a C_IDENTIFIER. All invalid keys will be reported as an event
+ when the container is starting. When a key exists in multiple
+ sources, the value associated with the last source will take
+ precedence. Values defined by an Env with a duplicate key
+ will take precedence. Cannot be updated.
+ items:
+ description: EnvFromSource represents the source of a set
+ of ConfigMaps
+ properties:
+ configMapRef:
+ description: The ConfigMap to select from
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap must be
+ defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ prefix:
+ description: An optional identifier to prepend to each
+ key in the ConfigMap. Must be a C_IDENTIFIER.
+ type: string
+ secretRef:
+ description: The Secret to select from
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ type: array
+ image:
+ description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images
+ This field is optional to allow higher level config management
+ to default or override container images in workload controllers
+ like Deployments and StatefulSets.'
+ type: string
+ imagePullPolicy:
+ description: 'Image pull policy. One of Always, Never, IfNotPresent.
+ Defaults to Always if :latest tag is specified, or IfNotPresent
+ otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images'
+ type: string
+ lifecycle:
+ description: Actions that the management system should take
+ in response to container lifecycle events. Cannot be updated.
+ properties:
+ postStart:
+ description: 'PostStart is called immediately after a container
+ is created. If the handler fails, the container is terminated
+ and restarted according to its restart policy. Other management
+ of the container blocks until the hook completes. More
+ info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for
+ the command is root ('/') in the container's
+ filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions
+ ('|', etc) won't work. To use a shell, you need
+ to explicitly call out to that shell. Exit status
+ of 0 is treated as live/healthy and non-zero is
+ unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to
+ the pod IP. You probably want to set "Host" in
+ httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the
+ host. Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ tcpSocket:
+ description: Deprecated. TCPSocket is NOT supported
+ as a LifecycleHandler and kept for the backward compatibility.
+ There are no validation of this field and lifecycle
+ hooks will fail in runtime when tcp handler is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ preStop:
+ description: 'PreStop is called immediately before a container
+ is terminated due to an API request or management event
+ such as liveness/startup probe failure, preemption, resource
+ contention, etc. The handler is not called if the container
+ crashes or exits. The Pod''s termination grace period
+ countdown begins before the PreStop hook is executed.
+ Regardless of the outcome of the handler, the container
+ will eventually terminate within the Pod''s termination
+ grace period (unless delayed by finalizers). Other management
+ of the container blocks until the hook completes or until
+ the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for
+ the command is root ('/') in the container's
+ filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions
+ ('|', etc) won't work. To use a shell, you need
+ to explicitly call out to that shell. Exit status
+ of 0 is treated as live/healthy and non-zero is
+ unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to
+ the pod IP. You probably want to set "Host" in
+ httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the
+ host. Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ tcpSocket:
+ description: Deprecated. TCPSocket is NOT supported
+ as a LifecycleHandler and kept for the backward compatibility.
+ There are no validation of this field and lifecycle
+ hooks will fail in runtime when tcp handler is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ type: object
+ livenessProbe:
+ description: 'Periodic probe of container liveness. Container
+ will be restarted if the probe fails. Cannot be updated. More
+ info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ name:
+ description: Name of the container specified as a DNS_LABEL.
+ Each container in a pod must have a unique name (DNS_LABEL).
+ Cannot be updated.
+ type: string
+ ports:
+ description: List of ports to expose from the container. Not
+ specifying a port here DOES NOT prevent that port from being
+ exposed. Any port which is listening on the default "0.0.0.0"
+ address inside a container will be accessible from the network.
+ Modifying this array with strategic merge patch may corrupt
+ the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255.
+ Cannot be updated.
+ items:
+ description: ContainerPort represents a network port in a
+ single container.
+ properties:
+ containerPort:
+ description: Number of port to expose on the pod's IP
+ address. This must be a valid port number, 0 < x < 65536.
+ format: int32
+ type: integer
+ hostIP:
+ description: What host IP to bind the external port to.
+ type: string
+ hostPort:
+ description: Number of port to expose on the host. If
+ specified, this must be a valid port number, 0 < x <
+ 65536. If HostNetwork is specified, this must match
+ ContainerPort. Most containers do not need this.
+ format: int32
+ type: integer
+ name:
+ description: If specified, this must be an IANA_SVC_NAME
+ and unique within the pod. Each named port in a pod
+ must have a unique name. Name for the port that can
+ be referred to by services.
+ type: string
+ protocol:
+ default: TCP
+ description: Protocol for port. Must be UDP, TCP, or SCTP.
+ Defaults to "TCP".
+ type: string
+ required:
+ - containerPort
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - containerPort
+ - protocol
+ x-kubernetes-list-type: map
+ readinessProbe:
+ description: 'Periodic probe of container service readiness.
+ Container will be removed from service endpoints if the probe
+ fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ resources:
+ description: 'Compute Resources required by this container.
+ Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount of compute
+ resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount of compute
+ resources required. If Requests is omitted for a container,
+ it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. More info:
+ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ securityContext:
+ description: 'SecurityContext defines the security options the
+ container should be run with. If set, the fields of SecurityContext
+ override the equivalent fields of PodSecurityContext. More
+ info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/'
+ properties:
+ allowPrivilegeEscalation:
+ description: 'AllowPrivilegeEscalation controls whether
+ a process can gain more privileges than its parent process.
+ This bool directly controls if the no_new_privs flag will
+ be set on the container process. AllowPrivilegeEscalation
+ is true always when the container is: 1) run as Privileged
+ 2) has CAP_SYS_ADMIN Note that this field cannot be set
+ when spec.os.name is windows.'
+ type: boolean
+ capabilities:
+ description: The capabilities to add/drop when running containers.
+ Defaults to the default set of capabilities granted by
+ the container runtime. Note that this field cannot be
+ set when spec.os.name is windows.
+ properties:
+ add:
+ description: Added capabilities
+ items:
+ description: Capability represent POSIX capabilities
+ type
+ type: string
+ type: array
+ drop:
+ description: Removed capabilities
+ items:
+ description: Capability represent POSIX capabilities
+ type
+ type: string
+ type: array
+ type: object
+ privileged:
+ description: Run container in privileged mode. Processes
+ in privileged containers are essentially equivalent to
+ root on the host. Defaults to false. Note that this field
+ cannot be set when spec.os.name is windows.
+ type: boolean
+ procMount:
+ description: procMount denotes the type of proc mount to
+ use for the containers. The default is DefaultProcMount
+ which uses the container runtime defaults for readonly
+ paths and masked paths. This requires the ProcMountType
+ feature flag to be enabled. Note that this field cannot
+ be set when spec.os.name is windows.
+ type: string
+ readOnlyRootFilesystem:
+ description: Whether this container has a read-only root
+ filesystem. Default is false. Note that this field cannot
+ be set when spec.os.name is windows.
+ type: boolean
+ runAsGroup:
+ description: The GID to run the entrypoint of the container
+ process. Uses runtime default if unset. May also be set
+ in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence. Note that this field cannot be set when
+ spec.os.name is windows.
+ format: int64
+ type: integer
+ runAsNonRoot:
+ description: Indicates that the container must run as a
+ non-root user. If true, the Kubelet will validate the
+ image at runtime to ensure that it does not run as UID
+ 0 (root) and fail to start the container if it does. If
+ unset or false, no such validation will be performed.
+ May also be set in PodSecurityContext. If set in both
+ SecurityContext and PodSecurityContext, the value specified
+ in SecurityContext takes precedence.
+ type: boolean
+ runAsUser:
+ description: The UID to run the entrypoint of the container
+ process. Defaults to user specified in image metadata
+ if unspecified. May also be set in PodSecurityContext. If
+ set in both SecurityContext and PodSecurityContext, the
+ value specified in SecurityContext takes precedence. Note
+ that this field cannot be set when spec.os.name is windows.
+ format: int64
+ type: integer
+ seLinuxOptions:
+ description: The SELinux context to be applied to the container.
+ If unspecified, the container runtime will allocate a
+ random SELinux context for each container. May also be
+ set in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence. Note that this field cannot be set when
+ spec.os.name is windows.
+ properties:
+ level:
+ description: Level is SELinux level label that applies
+ to the container.
+ type: string
+ role:
+ description: Role is a SELinux role label that applies
+ to the container.
+ type: string
+ type:
+ description: Type is a SELinux type label that applies
+ to the container.
+ type: string
+ user:
+ description: User is a SELinux user label that applies
+ to the container.
+ type: string
+ type: object
+ seccompProfile:
+ description: The seccomp options to use by this container.
+ If seccomp options are provided at both the pod & container
+ level, the container options override the pod options.
+ Note that this field cannot be set when spec.os.name is
+ windows.
+ properties:
+ localhostProfile:
+ description: localhostProfile indicates a profile defined
+ in a file on the node should be used. The profile
+ must be preconfigured on the node to work. Must be
+ a descending path, relative to the kubelet's configured
+ seccomp profile location. Must only be set if type
+ is "Localhost".
+ type: string
+ type:
+ description: "type indicates which kind of seccomp profile
+ will be applied. Valid options are: \n Localhost -
+ a profile defined in a file on the node should be
+ used. RuntimeDefault - the container runtime default
+ profile should be used. Unconfined - no profile should
+ be applied."
+ type: string
+ required:
+ - type
+ type: object
+ windowsOptions:
+ description: The Windows specific settings applied to all
+ containers. If unspecified, the options from the PodSecurityContext
+ will be used. If set in both SecurityContext and PodSecurityContext,
+ the value specified in SecurityContext takes precedence.
+ Note that this field cannot be set when spec.os.name is
+ linux.
+ properties:
+ gmsaCredentialSpec:
+ description: GMSACredentialSpec is where the GMSA admission
+ webhook (https://github.com/kubernetes-sigs/windows-gmsa)
+ inlines the contents of the GMSA credential spec named
+ by the GMSACredentialSpecName field.
+ type: string
+ gmsaCredentialSpecName:
+ description: GMSACredentialSpecName is the name of the
+ GMSA credential spec to use.
+ type: string
+ hostProcess:
+ description: HostProcess determines if a container should
+ be run as a 'Host Process' container. This field is
+ alpha-level and will only be honored by components
+ that enable the WindowsHostProcessContainers feature
+ flag. Setting this field without the feature flag
+ will result in errors when validating the Pod. All
+ of a Pod's containers must have the same effective
+ HostProcess value (it is not allowed to have a mix
+ of HostProcess containers and non-HostProcess containers). In
+ addition, if HostProcess is true then HostNetwork
+ must also be set to true.
+ type: boolean
+ runAsUserName:
+ description: The UserName in Windows to run the entrypoint
+ of the container process. Defaults to the user specified
+ in image metadata if unspecified. May also be set
+ in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence.
+ type: string
+ type: object
+ type: object
+ startupProbe:
+ description: 'StartupProbe indicates that the Pod has successfully
+ initialized. If specified, no other probes are executed until
+ this completes successfully. If this probe fails, the Pod
+ will be restarted, just as if the livenessProbe failed. This
+ can be used to provide different probe parameters at the beginning
+ of a Pod''s lifecycle, when it might take a long time to load
+ data or warm a cache, than during steady-state operation.
+ This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ stdin:
+ description: Whether this container should allocate a buffer
+ for stdin in the container runtime. If this is not set, reads
+ from stdin in the container will always result in EOF. Default
+ is false.
+ type: boolean
+ stdinOnce:
+ description: Whether the container runtime should close the
+ stdin channel after it has been opened by a single attach.
+ When stdin is true the stdin stream will remain open across
+ multiple attach sessions. If stdinOnce is set to true, stdin
+ is opened on container start, is empty until the first client
+ attaches to stdin, and then remains open and accepts data
+ until the client disconnects, at which time stdin is closed
+ and remains closed until the container is restarted. If this
+ flag is false, a container processes that reads from stdin
+ will never receive an EOF. Default is false
+ type: boolean
+ terminationMessagePath:
+ description: 'Optional: Path at which the file to which the
+ container''s termination message will be written is mounted
+ into the container''s filesystem. Message written is intended
+ to be brief final status, such as an assertion failure message.
+ Will be truncated by the node if greater than 4096 bytes.
+ The total message length across all containers will be limited
+ to 12kb. Defaults to /dev/termination-log. Cannot be updated.'
+ type: string
+ terminationMessagePolicy:
+ description: Indicate how the termination message should be
+ populated. File will use the contents of terminationMessagePath
+ to populate the container status message on both success and
+ failure. FallbackToLogsOnError will use the last chunk of
+ container log output if the termination message file is empty
+ and the container exited with an error. The log output is
+ limited to 2048 bytes or 80 lines, whichever is smaller. Defaults
+ to File. Cannot be updated.
+ type: string
+ tty:
+ description: Whether this container should allocate a TTY for
+ itself, also requires 'stdin' to be true. Default is false.
+ type: boolean
+ volumeDevices:
+ description: volumeDevices is the list of block devices to be
+ used by the container.
+ items:
+ description: volumeDevice describes a mapping of a raw block
+ device within a container.
+ properties:
+ devicePath:
+ description: devicePath is the path inside of the container
+ that the device will be mapped to.
+ type: string
+ name:
+ description: name must match the name of a persistentVolumeClaim
+ in the pod
+ type: string
+ required:
+ - devicePath
+ - name
+ type: object
+ type: array
+ volumeMounts:
+ description: Pod volumes to mount into the container's filesystem.
+ Cannot be updated.
+ items:
+ description: VolumeMount describes a mounting of a Volume
+ within a container.
+ properties:
+ mountPath:
+ description: Path within the container at which the volume
+ should be mounted. Must not contain ':'.
+ type: string
+ mountPropagation:
+ description: mountPropagation determines how mounts are
+ propagated from the host to container and the other
+ way around. When not set, MountPropagationNone is used.
+ This field is beta in 1.10.
+ type: string
+ name:
+ description: This must match the Name of a Volume.
+ type: string
+ readOnly:
+ description: Mounted read-only if true, read-write otherwise
+ (false or unspecified). Defaults to false.
+ type: boolean
+ subPath:
+ description: Path within the volume from which the container's
+ volume should be mounted. Defaults to "" (volume's root).
+ type: string
+ subPathExpr:
+ description: Expanded path within the volume from which
+ the container's volume should be mounted. Behaves similarly
+ to SubPath but environment variable references $(VAR_NAME)
+ are expanded using the container's environment. Defaults
+ to "" (volume's root). SubPathExpr and SubPath are mutually
+ exclusive.
+ type: string
+ required:
+ - mountPath
+ - name
+ type: object
+ type: array
+ workingDir:
+ description: Container's working directory. If not specified,
+ the container runtime's default will be used, which might
+ be configured in the container image. Cannot be updated.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ disableCompaction:
+ description: Disable prometheus compaction.
+ type: boolean
+ enableAdminAPI:
+ description: 'Enable access to prometheus web admin API. Defaults
+ to the value of `false`. WARNING: Enabling the admin APIs enables
+ mutating endpoints, to delete data, shutdown Prometheus, and more.
+ Enabling this should be done with care and the user is advised to
+ add additional authentication authorization via a proxy to ensure
+ only clients authorized to perform these actions can do so. For
+ more information see https://prometheus.io/docs/prometheus/latest/querying/api/#tsdb-admin-apis'
+ type: boolean
+ enableFeatures:
+ description: Enable access to Prometheus disabled features. By default,
+ no features are enabled. Enabling disabled features is entirely
+ outside the scope of what the maintainers will support and by doing
+ so, you accept that this behaviour may break at any time without
+ notice. For more information see https://prometheus.io/docs/prometheus/latest/disabled_features/
+ items:
+ type: string
+ type: array
+ enableRemoteWriteReceiver:
+ description: 'Enable Prometheus to be used as a receiver for the Prometheus
+ remote write protocol. Defaults to the value of `false`. WARNING:
+ This is not considered an efficient way of ingesting samples. Use
+ it with caution for specific low-volume use cases. It is not suitable
+ for replacing the ingestion via scraping and turning Prometheus
+ into a push-based metrics collection system. For more information
+ see https://prometheus.io/docs/prometheus/latest/querying/api/#remote-write-receiver
+ Only valid in Prometheus versions 2.33.0 and newer.'
+ type: boolean
+ enforcedBodySizeLimit:
+ description: 'EnforcedBodySizeLimit defines the maximum size of uncompressed
+ response body that will be accepted by Prometheus. Targets responding
+ with a body larger than this many bytes will cause the scrape to
+ fail. Example: 100MB. If defined, the limit will apply to all service/pod
+ monitors and probes. This is an experimental feature, this behaviour
+ could change or be removed in the future. Only valid in Prometheus
+ versions 2.28.0 and newer.'
+ pattern: (^0|([0-9]*[.])?[0-9]+((K|M|G|T|E|P)i?)?B)$
+ type: string
+ enforcedLabelLimit:
+ description: Per-scrape limit on number of labels that will be accepted
+ for a sample. If more than this number of labels are present post
+ metric-relabeling, the entire scrape will be treated as failed.
+ 0 means no limit. Only valid in Prometheus versions 2.27.0 and newer.
+ format: int64
+ type: integer
+ enforcedLabelNameLengthLimit:
+ description: Per-scrape limit on length of labels name that will be
+ accepted for a sample. If a label name is longer than this number
+ post metric-relabeling, the entire scrape will be treated as failed.
+ 0 means no limit. Only valid in Prometheus versions 2.27.0 and newer.
+ format: int64
+ type: integer
+ enforcedLabelValueLengthLimit:
+ description: Per-scrape limit on length of labels value that will
+ be accepted for a sample. If a label value is longer than this number
+ post metric-relabeling, the entire scrape will be treated as failed.
+ 0 means no limit. Only valid in Prometheus versions 2.27.0 and newer.
+ format: int64
+ type: integer
+ enforcedNamespaceLabel:
+ description: "EnforcedNamespaceLabel If set, a label will be added
+ to \n 1. all user-metrics (created by `ServiceMonitor`, `PodMonitor`
+ and `Probe` objects) and 2. in all `PrometheusRule` objects (except
+ the ones excluded in `prometheusRulesExcludedFromEnforce`) to *
+ alerting & recording rules and * the metrics used in their expressions
+ (`expr`). \n Label name is this field's value. Label value is the
+ namespace of the created object (mentioned above)."
+ type: string
+ enforcedSampleLimit:
+ description: EnforcedSampleLimit defines global limit on number of
+ scraped samples that will be accepted. This overrides any SampleLimit
+ set per ServiceMonitor or/and PodMonitor. It is meant to be used
+ by admins to enforce the SampleLimit to keep overall number of samples/series
+ under the desired limit. Note that if SampleLimit is lower that
+ value will be taken instead.
+ format: int64
+ type: integer
+ enforcedTargetLimit:
+ description: EnforcedTargetLimit defines a global limit on the number
+ of scraped targets. This overrides any TargetLimit set per ServiceMonitor
+ or/and PodMonitor. It is meant to be used by admins to enforce
+ the TargetLimit to keep the overall number of targets under the
+ desired limit. Note that if TargetLimit is lower, that value will
+ be taken instead, except if either value is zero, in which case
+ the non-zero value will be used. If both values are zero, no limit
+ is enforced.
+ format: int64
+ type: integer
+ evaluationInterval:
+ default: 30s
+ description: 'Interval between consecutive evaluations. Default: `30s`'
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ excludedFromEnforcement:
+ description: List of references to PodMonitor, ServiceMonitor, Probe
+ and PrometheusRule objects to be excluded from enforcing a namespace
+ label of origin. Applies only if enforcedNamespaceLabel set to true.
+ items:
+ description: ObjectReference references a PodMonitor, ServiceMonitor,
+ Probe or PrometheusRule object.
+ properties:
+ group:
+ default: monitoring.coreos.com
+ description: Group of the referent. When not specified, it defaults
+ to `monitoring.coreos.com`
+ enum:
+ - monitoring.coreos.com
+ type: string
+ name:
+ description: Name of the referent. When not set, all resources
+ are matched.
+ type: string
+ namespace:
+ description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
+ minLength: 1
+ type: string
+ resource:
+ description: Resource of the referent.
+ enum:
+ - prometheusrules
+ - servicemonitors
+ - podmonitors
+ - probes
+ type: string
+ required:
+ - namespace
+ - resource
+ type: object
+ type: array
+ exemplars:
+ description: Exemplars related settings that are runtime reloadable.
+ It requires to enable the exemplar storage feature to be effective.
+ properties:
+ maxSize:
+ description: Maximum number of exemplars stored in memory for
+ all series. If not set, Prometheus uses its default value. A
+ value of zero or less than zero disables the storage.
+ format: int64
+ type: integer
+ type: object
+ externalLabels:
+ additionalProperties:
+ type: string
+ description: The labels to add to any time series or alerts when communicating
+ with external systems (federation, remote storage, Alertmanager).
+ type: object
+ externalUrl:
+ description: The external URL the Prometheus instances will be available
+ under. This is necessary to generate correct URLs. This is necessary
+ if Prometheus is not served from root of a DNS name.
+ type: string
+ hostAliases:
+ description: Pods' hostAliases configuration
+ items:
+ description: HostAlias holds the mapping between IP and hostnames
+ that will be injected as an entry in the pod's hosts file.
+ properties:
+ hostnames:
+ description: Hostnames for the above IP address.
+ items:
+ type: string
+ type: array
+ ip:
+ description: IP address of the host file entry.
+ type: string
+ required:
+ - hostnames
+ - ip
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - ip
+ x-kubernetes-list-type: map
+ ignoreNamespaceSelectors:
+ description: IgnoreNamespaceSelectors if set to true will ignore NamespaceSelector
+ settings from all PodMonitor, ServiceMonitor and Probe objects.
+ They will only discover endpoints within the namespace of the PodMonitor,
+ ServiceMonitor and Probe objects. Defaults to false.
+ type: boolean
+ image:
+ description: Image if specified has precedence over baseImage, tag
+ and sha combinations. Specifying the version is still necessary
+ to ensure the Prometheus Operator knows what version of Prometheus
+ is being configured.
+ type: string
+ imagePullSecrets:
+ description: An optional list of references to secrets in the same
+ namespace to use for pulling prometheus and alertmanager images
+ from registries see http://kubernetes.io/docs/user-guide/images#specifying-imagepullsecrets-on-a-pod
+ items:
+ description: LocalObjectReference contains enough information to
+ let you locate the referenced object inside the same namespace.
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ initContainers:
+ description: 'InitContainers allows adding initContainers to the pod
+ definition. Those can be used to e.g. fetch secrets for injection
+ into the Prometheus configuration from external sources. Any errors
+ during the execution of an initContainer will lead to a restart
+ of the Pod. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
+ InitContainers described here modify an operator generated init
+ containers if they share the same name and modifications are done
+ via a strategic merge patch. The current init container name is:
+ `init-config-reloader`. Overriding init containers is entirely outside
+ the scope of what the maintainers will support and by doing so,
+ you accept that this behaviour may break at any time without notice.'
+ items:
+ description: A single application container that you want to run
+ within a pod.
+ properties:
+ args:
+ description: 'Arguments to the entrypoint. The container image''s
+ CMD is used if this is not provided. Variable references $(VAR_NAME)
+ are expanded using the container''s environment. If a variable
+ cannot be resolved, the reference in the input string will
+ be unchanged. Double $$ are reduced to a single $, which allows
+ for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
+ produce the string literal "$(VAR_NAME)". Escaped references
+ will never be expanded, regardless of whether the variable
+ exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
+ items:
+ type: string
+ type: array
+ command:
+ description: 'Entrypoint array. Not executed within a shell.
+ The container image''s ENTRYPOINT is used if this is not provided.
+ Variable references $(VAR_NAME) are expanded using the container''s
+ environment. If a variable cannot be resolved, the reference
+ in the input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME) syntax:
+ i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
+ Escaped references will never be expanded, regardless of whether
+ the variable exists or not. Cannot be updated. More info:
+ https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
+ items:
+ type: string
+ type: array
+ env:
+ description: List of environment variables to set in the container.
+ Cannot be updated.
+ items:
+ description: EnvVar represents an environment variable present
+ in a Container.
+ properties:
+ name:
+ description: Name of the environment variable. Must be
+ a C_IDENTIFIER.
+ type: string
+ value:
+ description: 'Variable references $(VAR_NAME) are expanded
+ using the previously defined environment variables in
+ the container and any service environment variables.
+ If a variable cannot be resolved, the reference in the
+ input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME)
+ syntax: i.e. "$$(VAR_NAME)" will produce the string
+ literal "$(VAR_NAME)". Escaped references will never
+ be expanded, regardless of whether the variable exists
+ or not. Defaults to "".'
+ type: string
+ valueFrom:
+ description: Source for the environment variable's value.
+ Cannot be used if value is not empty.
+ properties:
+ configMapKeyRef:
+ description: Selects a key of a ConfigMap.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ fieldRef:
+ description: 'Selects a field of the pod: supports
+ metadata.name, metadata.namespace, `metadata.labels['''']`,
+ `metadata.annotations['''']`, spec.nodeName,
+ spec.serviceAccountName, status.hostIP, status.podIP,
+ status.podIPs.'
+ properties:
+ apiVersion:
+ description: Version of the schema the FieldPath
+ is written in terms of, defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select in the
+ specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ resourceFieldRef:
+ description: 'Selects a resource of the container:
+ only resources limits and requests (limits.cpu,
+ limits.memory, limits.ephemeral-storage, requests.cpu,
+ requests.memory and requests.ephemeral-storage)
+ are currently supported.'
+ properties:
+ containerName:
+ description: 'Container name: required for volumes,
+ optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format of the
+ exposed resources, defaults to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ secretKeyRef:
+ description: Selects a key of a secret in the pod's
+ namespace
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ envFrom:
+ description: List of sources to populate environment variables
+ in the container. The keys defined within a source must be
+ a C_IDENTIFIER. All invalid keys will be reported as an event
+ when the container is starting. When a key exists in multiple
+ sources, the value associated with the last source will take
+ precedence. Values defined by an Env with a duplicate key
+ will take precedence. Cannot be updated.
+ items:
+ description: EnvFromSource represents the source of a set
+ of ConfigMaps
+ properties:
+ configMapRef:
+ description: The ConfigMap to select from
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap must be
+ defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ prefix:
+ description: An optional identifier to prepend to each
+ key in the ConfigMap. Must be a C_IDENTIFIER.
+ type: string
+ secretRef:
+ description: The Secret to select from
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ type: array
+ image:
+ description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images
+ This field is optional to allow higher level config management
+ to default or override container images in workload controllers
+ like Deployments and StatefulSets.'
+ type: string
+ imagePullPolicy:
+ description: 'Image pull policy. One of Always, Never, IfNotPresent.
+ Defaults to Always if :latest tag is specified, or IfNotPresent
+ otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images'
+ type: string
+ lifecycle:
+ description: Actions that the management system should take
+ in response to container lifecycle events. Cannot be updated.
+ properties:
+ postStart:
+ description: 'PostStart is called immediately after a container
+ is created. If the handler fails, the container is terminated
+ and restarted according to its restart policy. Other management
+ of the container blocks until the hook completes. More
+ info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for
+ the command is root ('/') in the container's
+ filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions
+ ('|', etc) won't work. To use a shell, you need
+ to explicitly call out to that shell. Exit status
+ of 0 is treated as live/healthy and non-zero is
+ unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to
+ the pod IP. You probably want to set "Host" in
+ httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the
+ host. Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ tcpSocket:
+ description: Deprecated. TCPSocket is NOT supported
+ as a LifecycleHandler and kept for the backward compatibility.
+ There are no validation of this field and lifecycle
+ hooks will fail in runtime when tcp handler is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ preStop:
+ description: 'PreStop is called immediately before a container
+ is terminated due to an API request or management event
+ such as liveness/startup probe failure, preemption, resource
+ contention, etc. The handler is not called if the container
+ crashes or exits. The Pod''s termination grace period
+ countdown begins before the PreStop hook is executed.
+ Regardless of the outcome of the handler, the container
+ will eventually terminate within the Pod''s termination
+ grace period (unless delayed by finalizers). Other management
+ of the container blocks until the hook completes or until
+ the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for
+ the command is root ('/') in the container's
+ filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions
+ ('|', etc) won't work. To use a shell, you need
+ to explicitly call out to that shell. Exit status
+ of 0 is treated as live/healthy and non-zero is
+ unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to
+ the pod IP. You probably want to set "Host" in
+ httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the
+ host. Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ tcpSocket:
+ description: Deprecated. TCPSocket is NOT supported
+ as a LifecycleHandler and kept for the backward compatibility.
+ There are no validation of this field and lifecycle
+ hooks will fail in runtime when tcp handler is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ type: object
+ livenessProbe:
+ description: 'Periodic probe of container liveness. Container
+ will be restarted if the probe fails. Cannot be updated. More
+ info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ name:
+ description: Name of the container specified as a DNS_LABEL.
+ Each container in a pod must have a unique name (DNS_LABEL).
+ Cannot be updated.
+ type: string
+ ports:
+ description: List of ports to expose from the container. Not
+ specifying a port here DOES NOT prevent that port from being
+ exposed. Any port which is listening on the default "0.0.0.0"
+ address inside a container will be accessible from the network.
+ Modifying this array with strategic merge patch may corrupt
+ the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255.
+ Cannot be updated.
+ items:
+ description: ContainerPort represents a network port in a
+ single container.
+ properties:
+ containerPort:
+ description: Number of port to expose on the pod's IP
+ address. This must be a valid port number, 0 < x < 65536.
+ format: int32
+ type: integer
+ hostIP:
+ description: What host IP to bind the external port to.
+ type: string
+ hostPort:
+ description: Number of port to expose on the host. If
+ specified, this must be a valid port number, 0 < x <
+ 65536. If HostNetwork is specified, this must match
+ ContainerPort. Most containers do not need this.
+ format: int32
+ type: integer
+ name:
+ description: If specified, this must be an IANA_SVC_NAME
+ and unique within the pod. Each named port in a pod
+ must have a unique name. Name for the port that can
+ be referred to by services.
+ type: string
+ protocol:
+ default: TCP
+ description: Protocol for port. Must be UDP, TCP, or SCTP.
+ Defaults to "TCP".
+ type: string
+ required:
+ - containerPort
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - containerPort
+ - protocol
+ x-kubernetes-list-type: map
+ readinessProbe:
+ description: 'Periodic probe of container service readiness.
+ Container will be removed from service endpoints if the probe
+ fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ resources:
+ description: 'Compute Resources required by this container.
+ Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount of compute
+ resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount of compute
+ resources required. If Requests is omitted for a container,
+ it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. More info:
+ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ securityContext:
+ description: 'SecurityContext defines the security options the
+ container should be run with. If set, the fields of SecurityContext
+ override the equivalent fields of PodSecurityContext. More
+ info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/'
+ properties:
+ allowPrivilegeEscalation:
+ description: 'AllowPrivilegeEscalation controls whether
+ a process can gain more privileges than its parent process.
+ This bool directly controls if the no_new_privs flag will
+ be set on the container process. AllowPrivilegeEscalation
+ is true always when the container is: 1) run as Privileged
+ 2) has CAP_SYS_ADMIN Note that this field cannot be set
+ when spec.os.name is windows.'
+ type: boolean
+ capabilities:
+ description: The capabilities to add/drop when running containers.
+ Defaults to the default set of capabilities granted by
+ the container runtime. Note that this field cannot be
+ set when spec.os.name is windows.
+ properties:
+ add:
+ description: Added capabilities
+ items:
+ description: Capability represent POSIX capabilities
+ type
+ type: string
+ type: array
+ drop:
+ description: Removed capabilities
+ items:
+ description: Capability represent POSIX capabilities
+ type
+ type: string
+ type: array
+ type: object
+ privileged:
+ description: Run container in privileged mode. Processes
+ in privileged containers are essentially equivalent to
+ root on the host. Defaults to false. Note that this field
+ cannot be set when spec.os.name is windows.
+ type: boolean
+ procMount:
+ description: procMount denotes the type of proc mount to
+ use for the containers. The default is DefaultProcMount
+ which uses the container runtime defaults for readonly
+ paths and masked paths. This requires the ProcMountType
+ feature flag to be enabled. Note that this field cannot
+ be set when spec.os.name is windows.
+ type: string
+ readOnlyRootFilesystem:
+ description: Whether this container has a read-only root
+ filesystem. Default is false. Note that this field cannot
+ be set when spec.os.name is windows.
+ type: boolean
+ runAsGroup:
+ description: The GID to run the entrypoint of the container
+ process. Uses runtime default if unset. May also be set
+ in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence. Note that this field cannot be set when
+ spec.os.name is windows.
+ format: int64
+ type: integer
+ runAsNonRoot:
+ description: Indicates that the container must run as a
+ non-root user. If true, the Kubelet will validate the
+ image at runtime to ensure that it does not run as UID
+ 0 (root) and fail to start the container if it does. If
+ unset or false, no such validation will be performed.
+ May also be set in PodSecurityContext. If set in both
+ SecurityContext and PodSecurityContext, the value specified
+ in SecurityContext takes precedence.
+ type: boolean
+ runAsUser:
+ description: The UID to run the entrypoint of the container
+ process. Defaults to user specified in image metadata
+ if unspecified. May also be set in PodSecurityContext. If
+ set in both SecurityContext and PodSecurityContext, the
+ value specified in SecurityContext takes precedence. Note
+ that this field cannot be set when spec.os.name is windows.
+ format: int64
+ type: integer
+ seLinuxOptions:
+ description: The SELinux context to be applied to the container.
+ If unspecified, the container runtime will allocate a
+ random SELinux context for each container. May also be
+ set in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence. Note that this field cannot be set when
+ spec.os.name is windows.
+ properties:
+ level:
+ description: Level is SELinux level label that applies
+ to the container.
+ type: string
+ role:
+ description: Role is a SELinux role label that applies
+ to the container.
+ type: string
+ type:
+ description: Type is a SELinux type label that applies
+ to the container.
+ type: string
+ user:
+ description: User is a SELinux user label that applies
+ to the container.
+ type: string
+ type: object
+ seccompProfile:
+ description: The seccomp options to use by this container.
+ If seccomp options are provided at both the pod & container
+ level, the container options override the pod options.
+ Note that this field cannot be set when spec.os.name is
+ windows.
+ properties:
+ localhostProfile:
+ description: localhostProfile indicates a profile defined
+ in a file on the node should be used. The profile
+ must be preconfigured on the node to work. Must be
+ a descending path, relative to the kubelet's configured
+ seccomp profile location. Must only be set if type
+ is "Localhost".
+ type: string
+ type:
+ description: "type indicates which kind of seccomp profile
+ will be applied. Valid options are: \n Localhost -
+ a profile defined in a file on the node should be
+ used. RuntimeDefault - the container runtime default
+ profile should be used. Unconfined - no profile should
+ be applied."
+ type: string
+ required:
+ - type
+ type: object
+ windowsOptions:
+ description: The Windows specific settings applied to all
+ containers. If unspecified, the options from the PodSecurityContext
+ will be used. If set in both SecurityContext and PodSecurityContext,
+ the value specified in SecurityContext takes precedence.
+ Note that this field cannot be set when spec.os.name is
+ linux.
+ properties:
+ gmsaCredentialSpec:
+ description: GMSACredentialSpec is where the GMSA admission
+ webhook (https://github.com/kubernetes-sigs/windows-gmsa)
+ inlines the contents of the GMSA credential spec named
+ by the GMSACredentialSpecName field.
+ type: string
+ gmsaCredentialSpecName:
+ description: GMSACredentialSpecName is the name of the
+ GMSA credential spec to use.
+ type: string
+ hostProcess:
+ description: HostProcess determines if a container should
+ be run as a 'Host Process' container. This field is
+ alpha-level and will only be honored by components
+ that enable the WindowsHostProcessContainers feature
+ flag. Setting this field without the feature flag
+ will result in errors when validating the Pod. All
+ of a Pod's containers must have the same effective
+ HostProcess value (it is not allowed to have a mix
+ of HostProcess containers and non-HostProcess containers). In
+ addition, if HostProcess is true then HostNetwork
+ must also be set to true.
+ type: boolean
+ runAsUserName:
+ description: The UserName in Windows to run the entrypoint
+ of the container process. Defaults to the user specified
+ in image metadata if unspecified. May also be set
+ in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence.
+ type: string
+ type: object
+ type: object
+ startupProbe:
+ description: 'StartupProbe indicates that the Pod has successfully
+ initialized. If specified, no other probes are executed until
+ this completes successfully. If this probe fails, the Pod
+ will be restarted, just as if the livenessProbe failed. This
+ can be used to provide different probe parameters at the beginning
+ of a Pod''s lifecycle, when it might take a long time to load
+ data or warm a cache, than during steady-state operation.
+ This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ stdin:
+ description: Whether this container should allocate a buffer
+ for stdin in the container runtime. If this is not set, reads
+ from stdin in the container will always result in EOF. Default
+ is false.
+ type: boolean
+ stdinOnce:
+ description: Whether the container runtime should close the
+ stdin channel after it has been opened by a single attach.
+ When stdin is true the stdin stream will remain open across
+ multiple attach sessions. If stdinOnce is set to true, stdin
+ is opened on container start, is empty until the first client
+ attaches to stdin, and then remains open and accepts data
+ until the client disconnects, at which time stdin is closed
+ and remains closed until the container is restarted. If this
+ flag is false, a container processes that reads from stdin
+ will never receive an EOF. Default is false
+ type: boolean
+ terminationMessagePath:
+ description: 'Optional: Path at which the file to which the
+ container''s termination message will be written is mounted
+ into the container''s filesystem. Message written is intended
+ to be brief final status, such as an assertion failure message.
+ Will be truncated by the node if greater than 4096 bytes.
+ The total message length across all containers will be limited
+ to 12kb. Defaults to /dev/termination-log. Cannot be updated.'
+ type: string
+ terminationMessagePolicy:
+ description: Indicate how the termination message should be
+ populated. File will use the contents of terminationMessagePath
+ to populate the container status message on both success and
+ failure. FallbackToLogsOnError will use the last chunk of
+ container log output if the termination message file is empty
+ and the container exited with an error. The log output is
+ limited to 2048 bytes or 80 lines, whichever is smaller. Defaults
+ to File. Cannot be updated.
+ type: string
+ tty:
+ description: Whether this container should allocate a TTY for
+ itself, also requires 'stdin' to be true. Default is false.
+ type: boolean
+ volumeDevices:
+ description: volumeDevices is the list of block devices to be
+ used by the container.
+ items:
+ description: volumeDevice describes a mapping of a raw block
+ device within a container.
+ properties:
+ devicePath:
+ description: devicePath is the path inside of the container
+ that the device will be mapped to.
+ type: string
+ name:
+ description: name must match the name of a persistentVolumeClaim
+ in the pod
+ type: string
+ required:
+ - devicePath
+ - name
+ type: object
+ type: array
+ volumeMounts:
+ description: Pod volumes to mount into the container's filesystem.
+ Cannot be updated.
+ items:
+ description: VolumeMount describes a mounting of a Volume
+ within a container.
+ properties:
+ mountPath:
+ description: Path within the container at which the volume
+ should be mounted. Must not contain ':'.
+ type: string
+ mountPropagation:
+ description: mountPropagation determines how mounts are
+ propagated from the host to container and the other
+ way around. When not set, MountPropagationNone is used.
+ This field is beta in 1.10.
+ type: string
+ name:
+ description: This must match the Name of a Volume.
+ type: string
+ readOnly:
+ description: Mounted read-only if true, read-write otherwise
+ (false or unspecified). Defaults to false.
+ type: boolean
+ subPath:
+ description: Path within the volume from which the container's
+ volume should be mounted. Defaults to "" (volume's root).
+ type: string
+ subPathExpr:
+ description: Expanded path within the volume from which
+ the container's volume should be mounted. Behaves similarly
+ to SubPath but environment variable references $(VAR_NAME)
+ are expanded using the container's environment. Defaults
+ to "" (volume's root). SubPathExpr and SubPath are mutually
+ exclusive.
+ type: string
+ required:
+ - mountPath
+ - name
+ type: object
+ type: array
+ workingDir:
+ description: Container's working directory. If not specified,
+ the container runtime's default will be used, which might
+ be configured in the container image. Cannot be updated.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ listenLocal:
+ description: ListenLocal makes the Prometheus server listen on loopback,
+ so that it does not bind against the Pod IP.
+ type: boolean
+ logFormat:
+ description: Log format for Prometheus to be configured with.
+ enum:
+ - ""
+ - logfmt
+ - json
+ type: string
+ logLevel:
+ description: Log level for Prometheus to be configured with.
+ enum:
+ - ""
+ - debug
+ - info
+ - warn
+ - error
+ type: string
+ minReadySeconds:
+ description: Minimum number of seconds for which a newly created pod
+ should be ready without any of its container crashing for it to
+ be considered available. Defaults to 0 (pod will be considered available
+ as soon as it is ready) This is an alpha field and requires enabling
+ StatefulSetMinReadySeconds feature gate.
+ format: int32
+ type: integer
+ nodeSelector:
+ additionalProperties:
+ type: string
+ description: Define which Nodes the Pods are scheduled on.
+ type: object
+ overrideHonorLabels:
+ description: When true, Prometheus resolves label conflicts by renaming
+ the labels in the scraped data to "exported_" for all
+ targets created from service and pod monitors. Otherwise the HonorLabels
+ field of the service or pod monitor applies.
+ type: boolean
+ overrideHonorTimestamps:
+ description: When true, Prometheus ignores the timestamps for all
+ the targets created from service and pod monitors. Otherwise the
+ HonorTimestamps field of the service or pod monitor applies.
+ type: boolean
+ paused:
+ description: When a Prometheus deployment is paused, no actions except
+ for deletion will be performed on the underlying objects.
+ type: boolean
+ podMetadata:
+ description: PodMetadata configures Labels and Annotations which are
+ propagated to the prometheus pods.
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: 'Annotations is an unstructured key value map stored
+ with a resource that may be set by external tools to store and
+ retrieve arbitrary metadata. They are not queryable and should
+ be preserved when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations'
+ type: object
+ labels:
+ additionalProperties:
+ type: string
+ description: 'Map of string keys and values that can be used to
+ organize and categorize (scope and select) objects. May match
+ selectors of replication controllers and services. More info:
+ http://kubernetes.io/docs/user-guide/labels'
+ type: object
+ name:
+ description: 'Name must be unique within a namespace. Is required
+ when creating resources, although some resources may allow a
+ client to request the generation of an appropriate name automatically.
+ Name is primarily intended for creation idempotence and configuration
+ definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names'
+ type: string
+ type: object
+ podMonitorNamespaceSelector:
+ description: Namespace's labels to match for PodMonitor discovery.
+ If nil, only check own namespace.
+ 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
+ x-kubernetes-map-type: atomic
+ podMonitorSelector:
+ description: '*Experimental* PodMonitors to be selected for target
+ discovery. *Deprecated:* if neither this nor serviceMonitorSelector
+ are specified, configuration is unmanaged.'
+ 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
+ x-kubernetes-map-type: atomic
+ portName:
+ description: Port name used for the pods and governing service. This
+ defaults to web
+ type: string
+ priorityClassName:
+ description: Priority class assigned to the Pods
+ type: string
+ probeNamespaceSelector:
+ description: '*Experimental* Namespaces to be selected for Probe discovery.
+ If nil, only check own namespace.'
+ 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
+ x-kubernetes-map-type: atomic
+ probeSelector:
+ description: '*Experimental* Probes to be selected for target discovery.'
+ 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
+ x-kubernetes-map-type: atomic
+ prometheusExternalLabelName:
+ description: Name of Prometheus external label used to denote Prometheus
+ instance name. Defaults to the value of `prometheus`. External label
+ will _not_ be added when value is set to empty string (`""`).
+ type: string
+ prometheusRulesExcludedFromEnforce:
+ description: 'PrometheusRulesExcludedFromEnforce - list of prometheus
+ rules to be excluded from enforcing of adding namespace labels.
+ Works only if enforcedNamespaceLabel set to true. Make sure both
+ ruleNamespace and ruleName are set for each pair. Deprecated: use
+ excludedFromEnforcement instead.'
+ items:
+ description: PrometheusRuleExcludeConfig enables users to configure
+ excluded PrometheusRule names and their namespaces to be ignored
+ while enforcing namespace label for alerts and metrics.
+ properties:
+ ruleName:
+ description: RuleNamespace - name of excluded rule
+ type: string
+ ruleNamespace:
+ description: RuleNamespace - namespace of excluded rule
+ type: string
+ required:
+ - ruleName
+ - ruleNamespace
+ type: object
+ type: array
+ query:
+ description: QuerySpec defines the query command line flags when starting
+ Prometheus.
+ properties:
+ lookbackDelta:
+ description: The delta difference allowed for retrieving metrics
+ during expression evaluations.
+ type: string
+ maxConcurrency:
+ description: Number of concurrent queries that can be run at once.
+ format: int32
+ type: integer
+ maxSamples:
+ description: Maximum number of samples a single query can load
+ into memory. Note that queries will fail if they would load
+ more samples than this into memory, so this also limits the
+ number of samples a query can return.
+ format: int32
+ type: integer
+ timeout:
+ description: Maximum time a query may take before being aborted.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ type: object
+ queryLogFile:
+ description: QueryLogFile specifies the file to which PromQL queries
+ are logged. If the filename has an empty path, e.g. 'query.log',
+ prometheus-operator will mount the file into an emptyDir volume
+ at `/var/log/prometheus`. If a full path is provided, e.g. /var/log/prometheus/query.log,
+ you must mount a volume in the specified directory and it must be
+ writable. This is because the prometheus container runs with a read-only
+ root filesystem for security reasons. Alternatively, the location
+ can be set to a stdout location such as `/dev/stdout` to log query
+ information to the default Prometheus log stream. This is only available
+ in versions of Prometheus >= 2.16.0. For more details, see the Prometheus
+ docs (https://prometheus.io/docs/guides/query-log/)
+ type: string
+ remoteRead:
+ description: remoteRead is the list of remote read configurations.
+ items:
+ description: RemoteReadSpec defines the configuration for Prometheus
+ to read back samples from a remote endpoint.
+ properties:
+ authorization:
+ description: Authorization section for remote read
+ properties:
+ credentials:
+ description: The secret's key that contains the credentials
+ of the request
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ credentialsFile:
+ description: File to read a secret from, mutually exclusive
+ with Credentials (from SafeAuthorization)
+ type: string
+ type:
+ description: Set the authentication type. Defaults to Bearer,
+ Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth for the URL.
+ properties:
+ password:
+ description: The secret in the service monitor namespace
+ that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor namespace
+ that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerToken:
+ description: Bearer token for remote read.
+ type: string
+ bearerTokenFile:
+ description: File to read bearer token for remote read.
+ type: string
+ headers:
+ additionalProperties:
+ type: string
+ description: Custom HTTP headers to be sent along with each
+ remote read request. Be aware that headers that are set by
+ Prometheus itself can't be overwritten. Only valid in Prometheus
+ versions 2.26.0 and newer.
+ type: object
+ name:
+ description: The name of the remote read queue, it must be unique
+ if specified. The name is used in metrics and logging in order
+ to differentiate read configurations. Only valid in Prometheus
+ versions 2.15.0 and newer.
+ type: string
+ oauth2:
+ description: OAuth2 for the URL. Only valid in Prometheus versions
+ 2.27.0 and newer.
+ properties:
+ clientId:
+ description: The secret or configmap containing the OAuth2
+ client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2 client secret
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ proxyUrl:
+ description: Optional ProxyURL.
+ type: string
+ readRecent:
+ description: Whether reads should be made for queries for time
+ ranges that the local storage should have complete data for.
+ type: boolean
+ remoteTimeout:
+ description: Timeout for requests to the remote read endpoint.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ requiredMatchers:
+ additionalProperties:
+ type: string
+ description: An optional list of equality matchers which have
+ to be present in a selector to query the remote read endpoint.
+ type: object
+ tlsConfig:
+ description: TLS Config to use for remote read.
+ properties:
+ ca:
+ description: Struct containing the CA cert to use for the
+ targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ caFile:
+ description: Path to the CA cert in the Prometheus container
+ to use for the targets.
+ type: string
+ cert:
+ description: Struct containing the client cert file for
+ the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ certFile:
+ description: Path to the client cert file in the Prometheus
+ container for the targets.
+ type: string
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keyFile:
+ description: Path to the client key file in the Prometheus
+ container for the targets.
+ type: string
+ keySecret:
+ description: Secret containing the client key file for the
+ targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the targets.
+ type: string
+ type: object
+ url:
+ description: The URL of the endpoint to query from.
+ type: string
+ required:
+ - url
+ type: object
+ type: array
+ remoteWrite:
+ description: remoteWrite is the list of remote write configurations.
+ items:
+ description: RemoteWriteSpec defines the configuration to write
+ samples from Prometheus to a remote endpoint.
+ properties:
+ authorization:
+ description: Authorization section for remote write
+ properties:
+ credentials:
+ description: The secret's key that contains the credentials
+ of the request
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ credentialsFile:
+ description: File to read a secret from, mutually exclusive
+ with Credentials (from SafeAuthorization)
+ type: string
+ type:
+ description: Set the authentication type. Defaults to Bearer,
+ Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: BasicAuth for the URL.
+ properties:
+ password:
+ description: The secret in the service monitor namespace
+ that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor namespace
+ that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerToken:
+ description: Bearer token for remote write.
+ type: string
+ bearerTokenFile:
+ description: File to read bearer token for remote write.
+ type: string
+ headers:
+ additionalProperties:
+ type: string
+ description: Custom HTTP headers to be sent along with each
+ remote write request. Be aware that headers that are set by
+ Prometheus itself can't be overwritten. Only valid in Prometheus
+ versions 2.25.0 and newer.
+ type: object
+ metadataConfig:
+ description: MetadataConfig configures the sending of series
+ metadata to the remote storage.
+ properties:
+ send:
+ description: Whether metric metadata is sent to the remote
+ storage or not.
+ type: boolean
+ sendInterval:
+ description: How frequently metric metadata is sent to the
+ remote storage.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ type: object
+ name:
+ description: The name of the remote write queue, it must be
+ unique if specified. The name is used in metrics and logging
+ in order to differentiate queues. Only valid in Prometheus
+ versions 2.15.0 and newer.
+ type: string
+ oauth2:
+ description: OAuth2 for the URL. Only valid in Prometheus versions
+ 2.27.0 and newer.
+ properties:
+ clientId:
+ description: The secret or configmap containing the OAuth2
+ client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2 client secret
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ proxyUrl:
+ description: Optional ProxyURL.
+ type: string
+ queueConfig:
+ description: QueueConfig allows tuning of the remote write queue
+ parameters.
+ properties:
+ batchSendDeadline:
+ description: BatchSendDeadline is the maximum time a sample
+ will wait in buffer.
+ type: string
+ capacity:
+ description: Capacity is the number of samples to buffer
+ per shard before we start dropping them.
+ type: integer
+ maxBackoff:
+ description: MaxBackoff is the maximum retry delay.
+ type: string
+ maxRetries:
+ description: MaxRetries is the maximum number of times to
+ retry a batch on recoverable errors.
+ type: integer
+ maxSamplesPerSend:
+ description: MaxSamplesPerSend is the maximum number of
+ samples per send.
+ type: integer
+ maxShards:
+ description: MaxShards is the maximum number of shards,
+ i.e. amount of concurrency.
+ type: integer
+ minBackoff:
+ description: MinBackoff is the initial retry delay. Gets
+ doubled for every retry.
+ type: string
+ minShards:
+ description: MinShards is the minimum number of shards,
+ i.e. amount of concurrency.
+ type: integer
+ retryOnRateLimit:
+ description: Retry upon receiving a 429 status code from
+ the remote-write storage. This is experimental feature
+ and might change in the future.
+ type: boolean
+ type: object
+ remoteTimeout:
+ description: Timeout for requests to the remote write endpoint.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ sendExemplars:
+ description: Enables sending of exemplars over remote write.
+ Note that exemplar-storage itself must be enabled using the
+ enableFeature option for exemplars to be scraped in the first
+ place. Only valid in Prometheus versions 2.27.0 and newer.
+ type: boolean
+ sigv4:
+ description: Sigv4 allows to configures AWS's Signature Verification
+ 4
+ properties:
+ accessKey:
+ description: AccessKey is the AWS API key. If blank, the
+ environment variable `AWS_ACCESS_KEY_ID` is used.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ profile:
+ description: Profile is the named AWS profile used to authenticate.
+ type: string
+ region:
+ description: Region is the AWS region. If blank, the region
+ from the default credentials chain used.
+ type: string
+ roleArn:
+ description: RoleArn is the named AWS profile used to authenticate.
+ type: string
+ secretKey:
+ description: SecretKey is the AWS API secret. If blank,
+ the environment variable `AWS_SECRET_ACCESS_KEY` is used.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ tlsConfig:
+ description: TLS Config to use for remote write.
+ properties:
+ ca:
+ description: Struct containing the CA cert to use for the
+ targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ caFile:
+ description: Path to the CA cert in the Prometheus container
+ to use for the targets.
+ type: string
+ cert:
+ description: Struct containing the client cert file for
+ the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ certFile:
+ description: Path to the client cert file in the Prometheus
+ container for the targets.
+ type: string
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keyFile:
+ description: Path to the client key file in the Prometheus
+ container for the targets.
+ type: string
+ keySecret:
+ description: Secret containing the client key file for the
+ targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the targets.
+ type: string
+ type: object
+ url:
+ description: The URL of the endpoint to send samples to.
+ type: string
+ writeRelabelConfigs:
+ description: The list of remote write relabel configurations.
+ items:
+ description: 'RelabelConfig allows dynamic rewriting of the
+ label set, being applied to samples before ingestion. It
+ defines ``-section of Prometheus
+ configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
+ properties:
+ action:
+ default: replace
+ description: Action to perform based on regex matching.
+ Default is 'replace'. uppercase and lowercase actions
+ require Prometheus >= 2.36.
+ enum:
+ - replace
+ - Replace
+ - keep
+ - Keep
+ - drop
+ - Drop
+ - hashmod
+ - HashMod
+ - labelmap
+ - LabelMap
+ - labeldrop
+ - LabelDrop
+ - labelkeep
+ - LabelKeep
+ - lowercase
+ - Lowercase
+ - uppercase
+ - Uppercase
+ type: string
+ modulus:
+ description: Modulus to take of the hash of the source
+ label values.
+ format: int64
+ type: integer
+ regex:
+ description: Regular expression against which the extracted
+ value is matched. Default is '(.*)'
+ type: string
+ replacement:
+ description: Replacement value against which a regex replace
+ is performed if the regular expression matches. Regex
+ capture groups are available. Default is '$1'
+ type: string
+ separator:
+ description: Separator placed between concatenated source
+ label values. default is ';'.
+ type: string
+ sourceLabels:
+ description: The source labels select values from existing
+ labels. Their content is concatenated using the configured
+ separator and matched against the configured regular
+ expression for the replace, keep, and drop actions.
+ items:
+ description: LabelName is a valid Prometheus label name
+ which may only contain ASCII letters, numbers, as
+ well as underscores.
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ type: string
+ type: array
+ targetLabel:
+ description: Label to which the resulting value is written
+ in a replace action. It is mandatory for replace actions.
+ Regex capture groups are available.
+ type: string
+ type: object
+ type: array
+ required:
+ - url
+ type: object
+ type: array
+ replicaExternalLabelName:
+ description: Name of Prometheus external label used to denote replica
+ name. Defaults to the value of `prometheus_replica`. External label
+ will _not_ be added when value is set to empty string (`""`).
+ type: string
+ replicas:
+ description: Number of replicas of each shard to deploy for a Prometheus
+ deployment. Number of replicas multiplied by shards is the total
+ number of Pods created.
+ format: int32
+ type: integer
+ resources:
+ description: Define resources requests and limits for single Pods.
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount of compute resources
+ allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount of compute
+ resources required. If Requests is omitted for a container,
+ it defaults to Limits if that is explicitly specified, otherwise
+ to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ retention:
+ description: Time duration Prometheus shall retain data for. Default
+ is '24h' if retentionSize is not set, and must match the regular
+ expression `[0-9]+(ms|s|m|h|d|w|y)` (milliseconds seconds minutes
+ hours days weeks years).
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ retentionSize:
+ description: Maximum amount of disk space used by blocks.
+ pattern: (^0|([0-9]*[.])?[0-9]+((K|M|G|T|E|P)i?)?B)$
+ type: string
+ routePrefix:
+ description: The route prefix Prometheus registers HTTP handlers for.
+ This is useful, if using ExternalURL and a proxy is rewriting HTTP
+ routes of a request, and the actual ExternalURL is still true, but
+ the server serves requests under a different route prefix. For example
+ for use with `kubectl proxy`.
+ type: string
+ ruleNamespaceSelector:
+ description: Namespaces to be selected for PrometheusRules discovery.
+ If unspecified, only the same namespace as the Prometheus object
+ is in is used.
+ 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
+ x-kubernetes-map-type: atomic
+ ruleSelector:
+ description: A selector to select which PrometheusRules to mount for
+ loading alerting/recording rules from. Until (excluding) Prometheus
+ Operator v0.24.0 Prometheus Operator will migrate any legacy rule
+ ConfigMaps to PrometheusRule custom resources selected by RuleSelector.
+ Make sure it does not match any config maps that you do not want
+ to be migrated.
+ 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
+ x-kubernetes-map-type: atomic
+ rules:
+ description: /--rules.*/ command-line arguments.
+ properties:
+ alert:
+ description: /--rules.alert.*/ command-line arguments
+ properties:
+ forGracePeriod:
+ description: Minimum duration between alert and restored 'for'
+ state. This is maintained only for alerts with configured
+ 'for' time greater than grace period.
+ type: string
+ forOutageTolerance:
+ description: Max time to tolerate prometheus outage for restoring
+ 'for' state of alert.
+ type: string
+ resendDelay:
+ description: Minimum amount of time to wait before resending
+ an alert to Alertmanager.
+ type: string
+ type: object
+ type: object
+ scrapeInterval:
+ default: 30s
+ description: 'Interval between consecutive scrapes. Default: `30s`'
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ scrapeTimeout:
+ description: Number of seconds to wait for target to respond before
+ erroring.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ secrets:
+ description: Secrets is a list of Secrets in the same namespace as
+ the Prometheus object, which shall be mounted into the Prometheus
+ Pods. The Secrets are mounted into /etc/prometheus/secrets/.
+ items:
+ type: string
+ type: array
+ securityContext:
+ description: SecurityContext holds pod-level security attributes and
+ common container settings. This defaults to the default PodSecurityContext.
+ properties:
+ fsGroup:
+ description: "A special supplemental group that applies to all
+ containers in a pod. Some volume types allow the Kubelet to
+ change the ownership of that volume to be owned by the pod:
+ \n 1. The owning GID will be the FSGroup 2. The setgid bit is
+ set (new files created in the volume will be owned by FSGroup)
+ 3. The permission bits are OR'd with rw-rw---- \n If unset,
+ the Kubelet will not modify the ownership and permissions of
+ any volume. Note that this field cannot be set when spec.os.name
+ is windows."
+ format: int64
+ type: integer
+ fsGroupChangePolicy:
+ description: 'fsGroupChangePolicy defines behavior of changing
+ ownership and permission of the volume before being exposed
+ inside Pod. This field will only apply to volume types which
+ support fsGroup based ownership(and permissions). It will have
+ no effect on ephemeral volume types such as: secret, configmaps
+ and emptydir. Valid values are "OnRootMismatch" and "Always".
+ If not specified, "Always" is used. Note that this field cannot
+ be set when spec.os.name is windows.'
+ type: string
+ runAsGroup:
+ description: The GID to run the entrypoint of the container process.
+ Uses runtime default if unset. May also be set in SecurityContext. If
+ set in both SecurityContext and PodSecurityContext, the value
+ specified in SecurityContext takes precedence for that container.
+ Note that this field cannot be set when spec.os.name is windows.
+ format: int64
+ type: integer
+ runAsNonRoot:
+ description: Indicates that the container must run as a non-root
+ user. If true, the Kubelet will validate the image at runtime
+ to ensure that it does not run as UID 0 (root) and fail to start
+ the container if it does. If unset or false, no such validation
+ will be performed. May also be set in SecurityContext. If set
+ in both SecurityContext and PodSecurityContext, the value specified
+ in SecurityContext takes precedence.
+ type: boolean
+ runAsUser:
+ description: The UID to run the entrypoint of the container process.
+ Defaults to user specified in image metadata if unspecified.
+ May also be set in SecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence for that container. Note that this field cannot
+ be set when spec.os.name is windows.
+ format: int64
+ type: integer
+ seLinuxOptions:
+ description: The SELinux context to be applied to all containers.
+ If unspecified, the container runtime will allocate a random
+ SELinux context for each container. May also be set in SecurityContext. If
+ set in both SecurityContext and PodSecurityContext, the value
+ specified in SecurityContext takes precedence for that container.
+ Note that this field cannot be set when spec.os.name is windows.
+ properties:
+ level:
+ description: Level is SELinux level label that applies to
+ the container.
+ type: string
+ role:
+ description: Role is a SELinux role label that applies to
+ the container.
+ type: string
+ type:
+ description: Type is a SELinux type label that applies to
+ the container.
+ type: string
+ user:
+ description: User is a SELinux user label that applies to
+ the container.
+ type: string
+ type: object
+ seccompProfile:
+ description: The seccomp options to use by the containers in this
+ pod. Note that this field cannot be set when spec.os.name is
+ windows.
+ properties:
+ localhostProfile:
+ description: localhostProfile indicates a profile defined
+ in a file on the node should be used. The profile must be
+ preconfigured on the node to work. Must be a descending
+ path, relative to the kubelet's configured seccomp profile
+ location. Must only be set if type is "Localhost".
+ type: string
+ type:
+ description: "type indicates which kind of seccomp profile
+ will be applied. Valid options are: \n Localhost - a profile
+ defined in a file on the node should be used. RuntimeDefault
+ - the container runtime default profile should be used.
+ Unconfined - no profile should be applied."
+ type: string
+ required:
+ - type
+ type: object
+ supplementalGroups:
+ description: A list of groups applied to the first process run
+ in each container, in addition to the container's primary GID. If
+ unspecified, no groups will be added to any container. Note
+ that this field cannot be set when spec.os.name is windows.
+ items:
+ format: int64
+ type: integer
+ type: array
+ sysctls:
+ description: Sysctls hold a list of namespaced sysctls used for
+ the pod. Pods with unsupported sysctls (by the container runtime)
+ might fail to launch. Note that this field cannot be set when
+ spec.os.name is windows.
+ items:
+ description: Sysctl defines a kernel parameter to be set
+ properties:
+ name:
+ description: Name of a property to set
+ type: string
+ value:
+ description: Value of a property to set
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ windowsOptions:
+ description: The Windows specific settings applied to all containers.
+ If unspecified, the options within a container's SecurityContext
+ will be used. If set in both SecurityContext and PodSecurityContext,
+ the value specified in SecurityContext takes precedence. Note
+ that this field cannot be set when spec.os.name is linux.
+ properties:
+ gmsaCredentialSpec:
+ description: GMSACredentialSpec is where the GMSA admission
+ webhook (https://github.com/kubernetes-sigs/windows-gmsa)
+ inlines the contents of the GMSA credential spec named by
+ the GMSACredentialSpecName field.
+ type: string
+ gmsaCredentialSpecName:
+ description: GMSACredentialSpecName is the name of the GMSA
+ credential spec to use.
+ type: string
+ hostProcess:
+ description: HostProcess determines if a container should
+ be run as a 'Host Process' container. This field is alpha-level
+ and will only be honored by components that enable the WindowsHostProcessContainers
+ feature flag. Setting this field without the feature flag
+ will result in errors when validating the Pod. All of a
+ Pod's containers must have the same effective HostProcess
+ value (it is not allowed to have a mix of HostProcess containers
+ and non-HostProcess containers). In addition, if HostProcess
+ is true then HostNetwork must also be set to true.
+ type: boolean
+ runAsUserName:
+ description: The UserName in Windows to run the entrypoint
+ of the container process. Defaults to the user specified
+ in image metadata if unspecified. May also be set in PodSecurityContext.
+ If set in both SecurityContext and PodSecurityContext, the
+ value specified in SecurityContext takes precedence.
+ type: string
+ type: object
+ type: object
+ serviceAccountName:
+ description: ServiceAccountName is the name of the ServiceAccount
+ to use to run the Prometheus Pods.
+ type: string
+ serviceMonitorNamespaceSelector:
+ description: Namespace's labels to match for ServiceMonitor discovery.
+ If nil, only check own namespace.
+ 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
+ x-kubernetes-map-type: atomic
+ serviceMonitorSelector:
+ description: ServiceMonitors to be selected for target discovery.
+ *Deprecated:* if neither this nor podMonitorSelector are specified,
+ configuration is unmanaged.
+ 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
+ x-kubernetes-map-type: atomic
+ sha:
+ description: 'SHA of Prometheus container image to be deployed. Defaults
+ to the value of `version`. Similar to a tag, but the SHA explicitly
+ deploys an immutable container image. Version and Tag are ignored
+ if SHA is set. Deprecated: use ''image'' instead. The image digest
+ can be specified as part of the image URL.'
+ type: string
+ shards:
+ description: 'EXPERIMENTAL: Number of shards to distribute targets
+ onto. Number of replicas multiplied by shards is the total number
+ of Pods created. Note that scaling down shards will not reshard
+ data onto remaining instances, it must be manually moved. Increasing
+ shards will not reshard data either but it will continue to be available
+ from the same instances. To query globally use Thanos sidecar and
+ Thanos querier or remote write data to a central location. Sharding
+ is done on the content of the `__address__` target meta-label.'
+ format: int32
+ type: integer
+ storage:
+ description: Storage spec to specify how storage shall be used.
+ properties:
+ disableMountSubPath:
+ description: 'Deprecated: subPath usage will be disabled by default
+ in a future release, this option will become unnecessary. DisableMountSubPath
+ allows to remove any subPath usage in volume mounts.'
+ type: boolean
+ emptyDir:
+ description: 'EmptyDirVolumeSource to be used by the Prometheus
+ StatefulSets. If specified, used in place of any volumeClaimTemplate.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir'
+ properties:
+ medium:
+ description: 'medium represents what type of storage medium
+ should back this directory. The default is "" which means
+ to use the node''s default medium. Must be an empty string
+ (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir'
+ type: string
+ sizeLimit:
+ anyOf:
+ - type: integer
+ - type: string
+ description: 'sizeLimit is the total amount of local storage
+ required for this EmptyDir volume. The size limit is also
+ applicable for memory medium. The maximum usage on memory
+ medium EmptyDir would be the minimum value between the SizeLimit
+ specified here and the sum of memory limits of all containers
+ in a pod. The default is nil which means that the limit
+ is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir'
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type: object
+ ephemeral:
+ description: 'EphemeralVolumeSource to be used by the Prometheus
+ StatefulSets. This is a beta field in k8s 1.21, for lower versions,
+ starting with k8s 1.19, it requires enabling the GenericEphemeralVolume
+ feature gate. More info: https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/#generic-ephemeral-volumes'
+ properties:
+ volumeClaimTemplate:
+ description: "Will be used to create a stand-alone PVC to
+ provision the volume. The pod in which this EphemeralVolumeSource
+ is embedded will be the owner of the PVC, i.e. the PVC will
+ be deleted together with the pod. The name of the PVC will
+ be `-` where `` is the
+ name from the `PodSpec.Volumes` array entry. Pod validation
+ will reject the pod if the concatenated name is not valid
+ for a PVC (for example, too long). \n An existing PVC with
+ that name that is not owned by the pod will *not* be used
+ for the pod to avoid using an unrelated volume by mistake.
+ Starting the pod is then blocked until the unrelated PVC
+ is removed. If such a pre-created PVC is meant to be used
+ by the pod, the PVC has to updated with an owner reference
+ to the pod once the pod exists. Normally this should not
+ be necessary, but it may be useful when manually reconstructing
+ a broken cluster. \n This field is read-only and no changes
+ will be made by Kubernetes to the PVC after it has been
+ created. \n Required, must not be nil."
+ properties:
+ metadata:
+ description: May contain labels and annotations that will
+ be copied into the PVC when creating it. No other fields
+ are allowed and will be rejected during validation.
+ type: object
+ spec:
+ description: The specification for the PersistentVolumeClaim.
+ The entire content is copied unchanged into the PVC
+ that gets created from this template. The same fields
+ as in a PersistentVolumeClaim are also valid here.
+ properties:
+ accessModes:
+ description: 'accessModes contains the desired access
+ modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+ items:
+ type: string
+ type: array
+ dataSource:
+ description: 'dataSource field can be used to specify
+ either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
+ * An existing PVC (PersistentVolumeClaim) If the
+ provisioner or an external controller can support
+ the specified data source, it will create a new
+ volume based on the contents of the specified data
+ source. If the AnyVolumeDataSource feature gate
+ is enabled, this field will always have the same
+ contents as the DataSourceRef field.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is
+ required.
+ type: string
+ kind:
+ description: Kind is the type of resource being
+ referenced
+ type: string
+ name:
+ description: Name is the name of resource being
+ referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ dataSourceRef:
+ description: 'dataSourceRef specifies the object from
+ which to populate the volume with data, if a non-empty
+ volume is desired. This may be any local object
+ from a non-empty API group (non core object) or
+ a PersistentVolumeClaim object. When this field
+ is specified, volume binding will only succeed if
+ the type of the specified object matches some installed
+ volume populator or dynamic provisioner. This field
+ will replace the functionality of the DataSource
+ field and as such if both fields are non-empty,
+ they must have the same value. For backwards compatibility,
+ both fields (DataSource and DataSourceRef) will
+ be set to the same value automatically if one of
+ them is empty and the other is non-empty. There
+ are two important differences between DataSource
+ and DataSourceRef: * While DataSource only allows
+ two specific types of objects, DataSourceRef allows
+ any non-core object, as well as PersistentVolumeClaim
+ objects. * While DataSource ignores disallowed values
+ (dropping them), DataSourceRef preserves all values,
+ and generates an error if a disallowed value is
+ specified. (Beta) Using this field requires the
+ AnyVolumeDataSource feature gate to be enabled.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is
+ required.
+ type: string
+ kind:
+ description: Kind is the type of resource being
+ referenced
+ type: string
+ name:
+ description: Name is the name of resource being
+ referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ resources:
+ description: 'resources represents the minimum resources
+ the volume should have. If RecoverVolumeExpansionFailure
+ feature is enabled users are allowed to specify
+ resource requirements that are lower than previous
+ value but must still be higher than capacity recorded
+ in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount
+ of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount
+ of compute resources required. If Requests is
+ omitted for a container, it defaults to Limits
+ if that is explicitly specified, otherwise to
+ an implementation-defined value. More info:
+ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ selector:
+ description: selector is a label query over volumes
+ to consider for binding.
+ 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
+ x-kubernetes-map-type: atomic
+ storageClassName:
+ description: 'storageClassName is the name of the
+ StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
+ type: string
+ volumeMode:
+ description: volumeMode defines what type of volume
+ is required by the claim. Value of Filesystem is
+ implied when not included in claim spec.
+ type: string
+ volumeName:
+ description: volumeName is the binding reference to
+ the PersistentVolume backing this claim.
+ type: string
+ type: object
+ required:
+ - spec
+ type: object
+ type: object
+ volumeClaimTemplate:
+ description: A PVC spec to be used by the Prometheus StatefulSets.
+ 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:
+ description: EmbeddedMetadata contains metadata relevant to
+ an EmbeddedResource.
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: 'Annotations is an unstructured key value
+ map stored with a resource that may be set by external
+ tools to store and retrieve arbitrary metadata. They
+ are not queryable and should be preserved when modifying
+ objects. More info: http://kubernetes.io/docs/user-guide/annotations'
+ type: object
+ labels:
+ additionalProperties:
+ type: string
+ description: 'Map of string keys and values that can be
+ used to organize and categorize (scope and select) objects.
+ May match selectors of replication controllers and services.
+ More info: http://kubernetes.io/docs/user-guide/labels'
+ type: object
+ name:
+ description: 'Name must be unique within a namespace.
+ Is required when creating resources, although some resources
+ may allow a client to request the generation of an appropriate
+ name automatically. Name is primarily intended for creation
+ idempotence and configuration definition. Cannot be
+ updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names'
+ type: string
+ type: object
+ spec:
+ description: 'Spec defines the desired characteristics of
+ a volume requested by a pod author. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
+ properties:
+ accessModes:
+ description: 'accessModes contains the desired access
+ modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+ items:
+ type: string
+ type: array
+ dataSource:
+ description: 'dataSource field can be used to specify
+ either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
+ * An existing PVC (PersistentVolumeClaim) If the provisioner
+ or an external controller can support the specified
+ data source, it will create a new volume based on the
+ contents of the specified data source. If the AnyVolumeDataSource
+ feature gate is enabled, this field will always have
+ the same contents as the DataSourceRef field.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is required.
+ type: string
+ kind:
+ description: Kind is the type of resource being referenced
+ type: string
+ name:
+ description: Name is the name of resource being referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ dataSourceRef:
+ description: 'dataSourceRef specifies the object from
+ which to populate the volume with data, if a non-empty
+ volume is desired. This may be any local object from
+ a non-empty API group (non core object) or a PersistentVolumeClaim
+ object. When this field is specified, volume binding
+ will only succeed if the type of the specified object
+ matches some installed volume populator or dynamic provisioner.
+ This field will replace the functionality of the DataSource
+ field and as such if both fields are non-empty, they
+ must have the same value. For backwards compatibility,
+ both fields (DataSource and DataSourceRef) will be set
+ to the same value automatically if one of them is empty
+ and the other is non-empty. There are two important
+ differences between DataSource and DataSourceRef: *
+ While DataSource only allows two specific types of objects,
+ DataSourceRef allows any non-core object, as well as
+ PersistentVolumeClaim objects. * While DataSource ignores
+ disallowed values (dropping them), DataSourceRef preserves
+ all values, and generates an error if a disallowed value
+ is specified. (Beta) Using this field requires the AnyVolumeDataSource
+ feature gate to be enabled.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is required.
+ type: string
+ kind:
+ description: Kind is the type of resource being referenced
+ type: string
+ name:
+ description: Name is the name of resource being referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ resources:
+ description: 'resources represents the minimum resources
+ the volume should have. If RecoverVolumeExpansionFailure
+ feature is enabled users are allowed to specify resource
+ requirements that are lower than previous value but
+ must still be higher than capacity recorded in the status
+ field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount
+ of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount
+ of compute resources required. If Requests is omitted
+ for a container, it defaults to Limits if that is
+ explicitly specified, otherwise to an implementation-defined
+ value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ selector:
+ description: selector is a label query over volumes to
+ consider for binding.
+ 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
+ x-kubernetes-map-type: atomic
+ storageClassName:
+ description: 'storageClassName is the name of the StorageClass
+ required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
+ type: string
+ volumeMode:
+ description: volumeMode defines what type of volume is
+ required by the claim. Value of Filesystem is implied
+ when not included in claim spec.
+ type: string
+ volumeName:
+ description: volumeName is the binding reference to the
+ PersistentVolume backing this claim.
+ type: string
+ type: object
+ status:
+ description: 'Status represents the current information/status
+ of a persistent volume claim. Read-only. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
+ properties:
+ accessModes:
+ description: 'accessModes contains the actual access modes
+ the volume backing the PVC has. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+ items:
+ type: string
+ type: array
+ allocatedResources:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: allocatedResources is the storage resource
+ within AllocatedResources tracks the capacity allocated
+ to a PVC. It may be larger than the actual capacity
+ when a volume expansion operation is requested. For
+ storage quota, the larger value from allocatedResources
+ and PVC.spec.resources is used. If allocatedResources
+ is not set, PVC.spec.resources alone is used for quota
+ calculation. If a volume expansion capacity request
+ is lowered, allocatedResources is only lowered if there
+ are no expansion operations in progress and if the actual
+ volume capacity is equal or lower than the requested
+ capacity. This is an alpha field and requires enabling
+ RecoverVolumeExpansionFailure feature.
+ type: object
+ capacity:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: capacity represents the actual resources
+ of the underlying volume.
+ type: object
+ conditions:
+ description: conditions is the current Condition of persistent
+ volume claim. If underlying persistent volume is being
+ resized then the Condition will be set to 'ResizeStarted'.
+ items:
+ description: PersistentVolumeClaimCondition contails
+ details about state of pvc
+ properties:
+ lastProbeTime:
+ description: lastProbeTime is the time we probed
+ the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: lastTransitionTime is the time the
+ condition transitioned from one status to another.
+ format: date-time
+ type: string
+ message:
+ description: message is the human-readable message
+ indicating details about last transition.
+ type: string
+ reason:
+ description: reason is a unique, this should be
+ a short, machine understandable string that gives
+ the reason for condition's last transition. If
+ it reports "ResizeStarted" that means the underlying
+ persistent volume is being resized.
+ type: string
+ status:
+ type: string
+ type:
+ description: PersistentVolumeClaimConditionType
+ is a valid value of PersistentVolumeClaimCondition.Type
+ type: string
+ required:
+ - status
+ - type
+ type: object
+ type: array
+ phase:
+ description: phase represents the current phase of PersistentVolumeClaim.
+ type: string
+ resizeStatus:
+ description: resizeStatus stores status of resize operation.
+ ResizeStatus is not set by default but when expansion
+ is complete resizeStatus is set to empty string by resize
+ controller or kubelet. This is an alpha field and requires
+ enabling RecoverVolumeExpansionFailure feature.
+ type: string
+ type: object
+ type: object
+ type: object
+ tag:
+ description: 'Tag of Prometheus container image to be deployed. Defaults
+ to the value of `version`. Version is ignored if Tag is set. Deprecated:
+ use ''image'' instead. The image tag can be specified as part of
+ the image URL.'
+ type: string
+ thanos:
+ description: "Thanos configuration allows configuring various aspects
+ of a Prometheus server in a Thanos environment. \n This section
+ is experimental, it may change significantly without deprecation
+ notice in any release. \n This is experimental and may change significantly
+ without backward compatibility in any release."
+ properties:
+ additionalArgs:
+ description: AdditionalArgs allows setting additional arguments
+ for the Thanos container. The arguments are passed as-is to
+ the Thanos container which may cause issues if they are invalid
+ or not supporeted the given Thanos version. In case of an argument
+ conflict (e.g. an argument which is already set by the operator
+ itself) or when providing an invalid argument the reconciliation
+ will fail and an error will be logged.
+ items:
+ description: Argument as part of the AdditionalArgs list.
+ properties:
+ name:
+ description: Name of the argument, e.g. "scrape.discovery-reload-interval".
+ minLength: 1
+ type: string
+ value:
+ description: Argument value, e.g. 30s. Can be empty for
+ name-only arguments (e.g. --storage.tsdb.no-lockfile)
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ baseImage:
+ description: 'Thanos base image if other than default. Deprecated:
+ use ''image'' instead'
+ type: string
+ grpcServerTlsConfig:
+ description: 'GRPCServerTLSConfig configures the gRPC server from
+ which Thanos Querier reads recorded rule data. Note: Currently
+ only the CAFile, CertFile, and KeyFile fields are supported.
+ Maps to the ''--grpc-server-tls-*'' CLI args.'
+ properties:
+ ca:
+ description: Struct containing the CA cert to use for the
+ targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ caFile:
+ description: Path to the CA cert in the Prometheus container
+ to use for the targets.
+ type: string
+ cert:
+ description: Struct containing the client cert file for the
+ targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ certFile:
+ description: Path to the client cert file in the Prometheus
+ container for the targets.
+ type: string
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keyFile:
+ description: Path to the client key file in the Prometheus
+ container for the targets.
+ type: string
+ keySecret:
+ description: Secret containing the client key file for the
+ targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the targets.
+ type: string
+ type: object
+ image:
+ description: Image if specified has precedence over baseImage,
+ tag and sha combinations. Specifying the version is still necessary
+ to ensure the Prometheus Operator knows what version of Thanos
+ is being configured.
+ type: string
+ listenLocal:
+ description: ListenLocal makes the Thanos sidecar listen on loopback,
+ so that it does not bind against the Pod IP.
+ type: boolean
+ logFormat:
+ description: LogFormat for Thanos sidecar to be configured with.
+ enum:
+ - ""
+ - logfmt
+ - json
+ type: string
+ logLevel:
+ description: LogLevel for Thanos sidecar to be configured with.
+ enum:
+ - ""
+ - debug
+ - info
+ - warn
+ - error
+ type: string
+ minTime:
+ description: MinTime for Thanos sidecar to be configured with.
+ Option can be a constant time in RFC3339 format or time duration
+ relative to current time, such as -1d or 2h45m. Valid duration
+ units are ms, s, m, h, d, w, y.
+ type: string
+ objectStorageConfig:
+ description: ObjectStorageConfig configures object storage in
+ Thanos. Alternative to ObjectStorageConfigFile, and lower order
+ priority.
+ properties:
+ key:
+ description: The key of the secret to select from. Must be
+ a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be
+ defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ objectStorageConfigFile:
+ description: ObjectStorageConfigFile specifies the path of the
+ object storage configuration file. When used alongside with
+ ObjectStorageConfig, ObjectStorageConfigFile takes precedence.
+ type: string
+ readyTimeout:
+ description: ReadyTimeout is the maximum time Thanos sidecar will
+ wait for Prometheus to start. Eg 10m
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ resources:
+ description: Resources defines the resource requirements for the
+ Thanos sidecar. If not provided, no requests/limits will be
+ set
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount of compute
+ resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount of compute
+ resources required. If Requests is omitted for a container,
+ it defaults to Limits if that is explicitly specified, otherwise
+ to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ sha:
+ description: 'SHA of Thanos container image to be deployed. Defaults
+ to the value of `version`. Similar to a tag, but the SHA explicitly
+ deploys an immutable container image. Version and Tag are ignored
+ if SHA is set. Deprecated: use ''image'' instead. The image
+ digest can be specified as part of the image URL.'
+ type: string
+ tag:
+ description: 'Tag of Thanos sidecar container image to be deployed.
+ Defaults to the value of `version`. Version is ignored if Tag
+ is set. Deprecated: use ''image'' instead. The image tag can
+ be specified as part of the image URL.'
+ type: string
+ tracingConfig:
+ description: TracingConfig configures tracing in Thanos. This
+ is an experimental feature, it may change in any upcoming release
+ in a breaking way.
+ properties:
+ key:
+ description: The key of the secret to select from. Must be
+ a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be
+ defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ tracingConfigFile:
+ description: TracingConfig specifies the path of the tracing configuration
+ file. When used alongside with TracingConfig, TracingConfigFile
+ takes precedence.
+ type: string
+ version:
+ description: Version describes the version of Thanos to use.
+ type: string
+ volumeMounts:
+ description: VolumeMounts allows configuration of additional VolumeMounts
+ on the output StatefulSet definition. VolumeMounts specified
+ will be appended to other VolumeMounts in the thanos-sidecar
+ container.
+ items:
+ description: VolumeMount describes a mounting of a Volume within
+ a container.
+ properties:
+ mountPath:
+ description: Path within the container at which the volume
+ should be mounted. Must not contain ':'.
+ type: string
+ mountPropagation:
+ description: mountPropagation determines how mounts are
+ propagated from the host to container and the other way
+ around. When not set, MountPropagationNone is used. This
+ field is beta in 1.10.
+ type: string
+ name:
+ description: This must match the Name of a Volume.
+ type: string
+ readOnly:
+ description: Mounted read-only if true, read-write otherwise
+ (false or unspecified). Defaults to false.
+ type: boolean
+ subPath:
+ description: Path within the volume from which the container's
+ volume should be mounted. Defaults to "" (volume's root).
+ type: string
+ subPathExpr:
+ description: Expanded path within the volume from which
+ the container's volume should be mounted. Behaves similarly
+ to SubPath but environment variable references $(VAR_NAME)
+ are expanded using the container's environment. Defaults
+ to "" (volume's root). SubPathExpr and SubPath are mutually
+ exclusive.
+ type: string
+ required:
+ - mountPath
+ - name
+ type: object
+ type: array
+ type: object
+ tolerations:
+ description: If specified, the pod's tolerations.
+ items:
+ description: The pod this Toleration is attached to tolerates any
+ taint that matches the triple using the matching
+ operator .
+ properties:
+ effect:
+ description: Effect indicates the taint effect to match. Empty
+ means match all taint effects. When specified, allowed values
+ are NoSchedule, PreferNoSchedule and NoExecute.
+ type: string
+ key:
+ description: Key is the taint key that the toleration applies
+ to. Empty means match all taint keys. If the key is empty,
+ operator must be Exists; this combination means to match all
+ values and all keys.
+ type: string
+ operator:
+ description: Operator represents a key's relationship to the
+ value. Valid operators are Exists and Equal. Defaults to Equal.
+ Exists is equivalent to wildcard for value, so that a pod
+ can tolerate all taints of a particular category.
+ type: string
+ tolerationSeconds:
+ description: TolerationSeconds represents the period of time
+ the toleration (which must be of effect NoExecute, otherwise
+ this field is ignored) tolerates the taint. By default, it
+ is not set, which means tolerate the taint forever (do not
+ evict). Zero and negative values will be treated as 0 (evict
+ immediately) by the system.
+ format: int64
+ type: integer
+ value:
+ description: Value is the taint value the toleration matches
+ to. If the operator is Exists, the value should be empty,
+ otherwise just a regular string.
+ type: string
+ type: object
+ type: array
+ topologySpreadConstraints:
+ description: If specified, the pod's topology spread constraints.
+ items:
+ description: TopologySpreadConstraint specifies how to spread matching
+ pods among the given topology.
+ properties:
+ labelSelector:
+ description: LabelSelector is used to find matching pods. Pods
+ that match this label selector are counted to determine the
+ number of pods in their corresponding topology domain.
+ 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
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: MatchLabelKeys is a set of pod label keys to select
+ the pods over which spreading will be calculated. The keys
+ are used to lookup values from the incoming pod labels, those
+ key-value labels are ANDed with labelSelector to select the
+ group of existing pods over which spreading will be calculated
+ for the incoming pod. Keys that don't exist in the incoming
+ pod labels will be ignored. A null or empty list means only
+ match against labelSelector.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ maxSkew:
+ description: 'MaxSkew describes the degree to which pods may
+ be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`,
+ it is the maximum permitted difference between the number
+ of matching pods in the target topology and the global minimum.
+ The global minimum is the minimum number of matching pods
+ in an eligible domain or zero if the number of eligible domains
+ is less than MinDomains. For example, in a 3-zone cluster,
+ MaxSkew is set to 1, and pods with the same labelSelector
+ spread as 2/2/1: In this case, the global minimum is 1. |
+ zone1 | zone2 | zone3 | | P P | P P | P | - if MaxSkew
+ is 1, incoming pod can only be scheduled to zone3 to become
+ 2/2/2; scheduling it onto zone1(zone2) would make the ActualSkew(3-1)
+ on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming
+ pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`,
+ it is used to give higher precedence to topologies that satisfy
+ it. It''s a required field. Default value is 1 and 0 is not
+ allowed.'
+ format: int32
+ type: integer
+ minDomains:
+ description: "MinDomains indicates a minimum number of eligible
+ domains. When the number of eligible domains with matching
+ topology keys is less than minDomains, Pod Topology Spread
+ treats \"global minimum\" as 0, and then the calculation of
+ Skew is performed. And when the number of eligible domains
+ with matching topology keys equals or greater than minDomains,
+ this value has no effect on scheduling. As a result, when
+ the number of eligible domains is less than minDomains, scheduler
+ won't schedule more than maxSkew Pods to those domains. If
+ value is nil, the constraint behaves as if MinDomains is equal
+ to 1. Valid values are integers greater than 0. When value
+ is not nil, WhenUnsatisfiable must be DoNotSchedule. \n For
+ example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains
+ is set to 5 and pods with the same labelSelector spread as
+ 2/2/2: | zone1 | zone2 | zone3 | | P P | P P | P P |
+ The number of domains is less than 5(MinDomains), so \"global
+ minimum\" is treated as 0. In this situation, new pod with
+ the same labelSelector cannot be scheduled, because computed
+ skew will be 3(3 - 0) if new Pod is scheduled to any of the
+ three zones, it will violate MaxSkew. \n This is a beta field
+ and requires the MinDomainsInPodTopologySpread feature gate
+ to be enabled (enabled by default)."
+ format: int32
+ type: integer
+ nodeAffinityPolicy:
+ description: "NodeAffinityPolicy indicates how we will treat
+ Pod's nodeAffinity/nodeSelector when calculating pod topology
+ spread skew. Options are: - Honor: only nodes matching nodeAffinity/nodeSelector
+ are included in the calculations. - Ignore: nodeAffinity/nodeSelector
+ are ignored. All nodes are included in the calculations. \n
+ If this value is nil, the behavior is equivalent to the Honor
+ policy. This is a alpha-level feature enabled by the NodeInclusionPolicyInPodTopologySpread
+ feature flag."
+ type: string
+ nodeTaintsPolicy:
+ description: "NodeTaintsPolicy indicates how we will treat node
+ taints when calculating pod topology spread skew. Options
+ are: - Honor: nodes without taints, along with tainted nodes
+ for which the incoming pod has a toleration, are included.
+ - Ignore: node taints are ignored. All nodes are included.
+ \n If this value is nil, the behavior is equivalent to the
+ Ignore policy. This is a alpha-level feature enabled by the
+ NodeInclusionPolicyInPodTopologySpread feature flag."
+ type: string
+ topologyKey:
+ description: TopologyKey is the key of node labels. Nodes that
+ have a label with this key and identical values are considered
+ to be in the same topology. We consider each
+ as a "bucket", and try to put balanced number of pods into
+ each bucket. We define a domain as a particular instance of
+ a topology. Also, we define an eligible domain as a domain
+ whose nodes meet the requirements of nodeAffinityPolicy and
+ nodeTaintsPolicy. e.g. If TopologyKey is "kubernetes.io/hostname",
+ each Node is a domain of that topology. And, if TopologyKey
+ is "topology.kubernetes.io/zone", each zone is a domain of
+ that topology. It's a required field.
+ type: string
+ whenUnsatisfiable:
+ description: 'WhenUnsatisfiable indicates how to deal with a
+ pod if it doesn''t satisfy the spread constraint. - DoNotSchedule
+ (default) tells the scheduler not to schedule it. - ScheduleAnyway
+ tells the scheduler to schedule the pod in any location, but
+ giving higher precedence to topologies that would help reduce
+ the skew. A constraint is considered "Unsatisfiable" for an
+ incoming pod if and only if every possible node assignment
+ for that pod would violate "MaxSkew" on some topology. For
+ example, in a 3-zone cluster, MaxSkew is set to 1, and pods
+ with the same labelSelector spread as 3/1/1: | zone1 | zone2
+ | zone3 | | P P P | P | P | If WhenUnsatisfiable is
+ set to DoNotSchedule, incoming pod can only be scheduled to
+ zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on
+ zone2(zone3) satisfies MaxSkew(1). In other words, the cluster
+ can still be imbalanced, but scheduler won''t make it *more*
+ imbalanced. It''s a required field.'
+ type: string
+ required:
+ - maxSkew
+ - topologyKey
+ - whenUnsatisfiable
+ type: object
+ type: array
+ version:
+ description: Version of Prometheus to be deployed.
+ type: string
+ volumeMounts:
+ description: VolumeMounts allows configuration of additional VolumeMounts
+ on the output StatefulSet definition. VolumeMounts specified will
+ be appended to other VolumeMounts in the prometheus container, that
+ are generated as a result of StorageSpec objects.
+ items:
+ description: VolumeMount describes a mounting of a Volume within
+ a container.
+ properties:
+ mountPath:
+ description: Path within the container at which the volume should
+ be mounted. Must not contain ':'.
+ type: string
+ mountPropagation:
+ description: mountPropagation determines how mounts are propagated
+ from the host to container and the other way around. When
+ not set, MountPropagationNone is used. This field is beta
+ in 1.10.
+ type: string
+ name:
+ description: This must match the Name of a Volume.
+ type: string
+ readOnly:
+ description: Mounted read-only if true, read-write otherwise
+ (false or unspecified). Defaults to false.
+ type: boolean
+ subPath:
+ description: Path within the volume from which the container's
+ volume should be mounted. Defaults to "" (volume's root).
+ type: string
+ subPathExpr:
+ description: Expanded path within the volume from which the
+ container's volume should be mounted. Behaves similarly to
+ SubPath but environment variable references $(VAR_NAME) are
+ expanded using the container's environment. Defaults to ""
+ (volume's root). SubPathExpr and SubPath are mutually exclusive.
+ type: string
+ required:
+ - mountPath
+ - name
+ type: object
+ type: array
+ volumes:
+ description: Volumes allows configuration of additional volumes on
+ the output StatefulSet definition. Volumes specified will be appended
+ to other volumes that are generated as a result of StorageSpec objects.
+ items:
+ description: Volume represents a named volume in a pod that may
+ be accessed by any container in the pod.
+ properties:
+ awsElasticBlockStore:
+ description: 'awsElasticBlockStore represents an AWS Disk resource
+ that is attached to a kubelet''s host machine and then exposed
+ to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore'
+ properties:
+ fsType:
+ description: 'fsType is the filesystem type of the volume
+ that you want to mount. Tip: Ensure that the filesystem
+ type is supported by the host operating system. Examples:
+ "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore
+ TODO: how do we prevent errors in the filesystem from
+ compromising the machine'
+ type: string
+ partition:
+ description: 'partition is the partition in the volume that
+ you want to mount. If omitted, the default is to mount
+ by volume name. Examples: For volume /dev/sda1, you specify
+ the partition as "1". Similarly, the volume partition
+ for /dev/sda is "0" (or you can leave the property empty).'
+ format: int32
+ type: integer
+ readOnly:
+ description: 'readOnly value true will force the readOnly
+ setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore'
+ type: boolean
+ volumeID:
+ description: 'volumeID is unique ID of the persistent disk
+ resource in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore'
+ type: string
+ required:
+ - volumeID
+ type: object
+ azureDisk:
+ description: azureDisk represents an Azure Data Disk mount on
+ the host and bind mount to the pod.
+ properties:
+ cachingMode:
+ description: 'cachingMode is the Host Caching mode: None,
+ Read Only, Read Write.'
+ type: string
+ diskName:
+ description: diskName is the Name of the data disk in the
+ blob storage
+ type: string
+ diskURI:
+ description: diskURI is the URI of data disk in the blob
+ storage
+ type: string
+ fsType:
+ description: fsType is Filesystem type to mount. Must be
+ a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ kind:
+ description: 'kind expected values are Shared: multiple
+ blob disks per storage account Dedicated: single blob
+ disk per storage account Managed: azure managed data
+ disk (only in managed availability set). defaults to shared'
+ type: string
+ readOnly:
+ description: readOnly Defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ required:
+ - diskName
+ - diskURI
+ type: object
+ azureFile:
+ description: azureFile represents an Azure File Service mount
+ on the host and bind mount to the pod.
+ properties:
+ readOnly:
+ description: readOnly defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretName:
+ description: secretName is the name of secret that contains
+ Azure Storage Account Name and Key
+ type: string
+ shareName:
+ description: shareName is the azure share Name
+ type: string
+ required:
+ - secretName
+ - shareName
+ type: object
+ cephfs:
+ description: cephFS represents a Ceph FS mount on the host that
+ shares a pod's lifetime
+ properties:
+ monitors:
+ description: 'monitors is Required: Monitors is a collection
+ of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ items:
+ type: string
+ type: array
+ path:
+ description: 'path is Optional: Used as the mounted root,
+ rather than the full Ceph tree, default is /'
+ type: string
+ readOnly:
+ description: 'readOnly is Optional: Defaults to false (read/write).
+ ReadOnly here will force the ReadOnly setting in VolumeMounts.
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ type: boolean
+ secretFile:
+ description: 'secretFile is Optional: SecretFile is the
+ path to key ring for User, default is /etc/ceph/user.secret
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ type: string
+ secretRef:
+ description: 'secretRef is Optional: SecretRef is reference
+ to the authentication secret for User, default is empty.
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ user:
+ description: 'user is optional: User is the rados user name,
+ default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ type: string
+ required:
+ - monitors
+ type: object
+ cinder:
+ description: 'cinder represents a cinder volume attached and
+ mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md'
+ properties:
+ fsType:
+ description: 'fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Examples: "ext4", "xfs", "ntfs". Implicitly inferred to
+ be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md'
+ type: string
+ readOnly:
+ description: 'readOnly defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ More info: https://examples.k8s.io/mysql-cinder-pd/README.md'
+ type: boolean
+ secretRef:
+ description: 'secretRef is optional: points to a secret
+ object containing parameters used to connect to OpenStack.'
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ volumeID:
+ description: 'volumeID used to identify the volume in cinder.
+ More info: https://examples.k8s.io/mysql-cinder-pd/README.md'
+ type: string
+ required:
+ - volumeID
+ type: object
+ configMap:
+ description: configMap represents a configMap that should populate
+ this volume
+ properties:
+ defaultMode:
+ description: 'defaultMode is optional: mode bits used to
+ set permissions on created files by default. Must be an
+ octal value between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. Defaults to
+ 0644. Directories within the path are not affected by
+ this setting. This might be in conflict with other options
+ that affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ items:
+ description: items if unspecified, each key-value pair in
+ the Data field of the referenced ConfigMap will be projected
+ into the volume as a file whose name is the key and content
+ is the value. If specified, the listed keys will be projected
+ into the specified paths, and unlisted keys will not be
+ present. If a key is specified which is not present in
+ the ConfigMap, the volume setup will error unless it is
+ marked optional. Paths must be relative and may not contain
+ the '..' path or start with '..'.
+ items:
+ description: Maps a string key to a path within a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: 'mode is Optional: mode bits used to
+ set permissions on this file. Must be an octal value
+ between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. If not
+ specified, the volume defaultMode will be used.
+ This might be in conflict with other options that
+ affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: path is the relative path of the file
+ to map the key to. May not be an absolute path.
+ May not contain the path element '..'. May not start
+ with the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: optional specify whether the ConfigMap or its
+ keys must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ csi:
+ description: csi (Container Storage Interface) represents ephemeral
+ storage that is handled by certain external CSI drivers (Beta
+ feature).
+ properties:
+ driver:
+ description: driver is the name of the CSI driver that handles
+ this volume. Consult with your admin for the correct name
+ as registered in the cluster.
+ type: string
+ fsType:
+ description: fsType to mount. Ex. "ext4", "xfs", "ntfs".
+ If not provided, the empty value is passed to the associated
+ CSI driver which will determine the default filesystem
+ to apply.
+ type: string
+ nodePublishSecretRef:
+ description: nodePublishSecretRef is a reference to the
+ secret object containing sensitive information to pass
+ to the CSI driver to complete the CSI NodePublishVolume
+ and NodeUnpublishVolume calls. This field is optional,
+ and may be empty if no secret is required. If the secret
+ object contains more than one secret, all secret references
+ are passed.
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ readOnly:
+ description: readOnly specifies a read-only configuration
+ for the volume. Defaults to false (read/write).
+ type: boolean
+ volumeAttributes:
+ additionalProperties:
+ type: string
+ description: volumeAttributes stores driver-specific properties
+ that are passed to the CSI driver. Consult your driver's
+ documentation for supported values.
+ type: object
+ required:
+ - driver
+ type: object
+ downwardAPI:
+ description: downwardAPI represents downward API about the pod
+ that should populate this volume
+ properties:
+ defaultMode:
+ description: 'Optional: mode bits to use on created files
+ by default. Must be a Optional: mode bits used to set
+ permissions on created files by default. Must be an octal
+ value between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. Defaults to
+ 0644. Directories within the path are not affected by
+ this setting. This might be in conflict with other options
+ that affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ items:
+ description: Items is a list of downward API volume file
+ items:
+ description: DownwardAPIVolumeFile represents information
+ to create the file containing the pod field
+ properties:
+ fieldRef:
+ description: 'Required: Selects a field of the pod:
+ only annotations, labels, name and namespace are
+ supported.'
+ properties:
+ apiVersion:
+ description: Version of the schema the FieldPath
+ is written in terms of, defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select in the
+ specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ mode:
+ description: 'Optional: mode bits used to set permissions
+ on this file, must be an octal value between 0000
+ and 0777 or a decimal value between 0 and 511. YAML
+ accepts both octal and decimal values, JSON requires
+ decimal values for mode bits. If not specified,
+ the volume defaultMode will be used. This might
+ be in conflict with other options that affect the
+ file mode, like fsGroup, and the result can be other
+ mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: 'Required: Path is the relative path
+ name of the file to be created. Must not be absolute
+ or contain the ''..'' path. Must be utf-8 encoded.
+ The first item of the relative path must not start
+ with ''..'''
+ type: string
+ resourceFieldRef:
+ description: 'Selects a resource of the container:
+ only resources limits and requests (limits.cpu,
+ limits.memory, requests.cpu and requests.memory)
+ are currently supported.'
+ properties:
+ containerName:
+ description: 'Container name: required for volumes,
+ optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format of the
+ exposed resources, defaults to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ required:
+ - path
+ type: object
+ type: array
+ type: object
+ emptyDir:
+ description: 'emptyDir represents a temporary directory that
+ shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir'
+ properties:
+ medium:
+ description: 'medium represents what type of storage medium
+ should back this directory. The default is "" which means
+ to use the node''s default medium. Must be an empty string
+ (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir'
+ type: string
+ sizeLimit:
+ anyOf:
+ - type: integer
+ - type: string
+ description: 'sizeLimit is the total amount of local storage
+ required for this EmptyDir volume. The size limit is also
+ applicable for memory medium. The maximum usage on memory
+ medium EmptyDir would be the minimum value between the
+ SizeLimit specified here and the sum of memory limits
+ of all containers in a pod. The default is nil which means
+ that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir'
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type: object
+ ephemeral:
+ description: "ephemeral represents a volume that is handled
+ by a cluster storage driver. The volume's lifecycle is tied
+ to the pod that defines it - it will be created before the
+ pod starts, and deleted when the pod is removed. \n Use this
+ if: a) the volume is only needed while the pod runs, b) features
+ of normal volumes like restoring from snapshot or capacity
+ tracking are needed, c) the storage driver is specified through
+ a storage class, and d) the storage driver supports dynamic
+ volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource
+ for more information on the connection between this volume
+ type and PersistentVolumeClaim). \n Use PersistentVolumeClaim
+ or one of the vendor-specific APIs for volumes that persist
+ for longer than the lifecycle of an individual pod. \n Use
+ CSI for light-weight local ephemeral volumes if the CSI driver
+ is meant to be used that way - see the documentation of the
+ driver for more information. \n A pod can use both types of
+ ephemeral volumes and persistent volumes at the same time."
+ properties:
+ volumeClaimTemplate:
+ description: "Will be used to create a stand-alone PVC to
+ provision the volume. The pod in which this EphemeralVolumeSource
+ is embedded will be the owner of the PVC, i.e. the PVC
+ will be deleted together with the pod. The name of the
+ PVC will be `-` where `` is the name from the `PodSpec.Volumes` array entry.
+ Pod validation will reject the pod if the concatenated
+ name is not valid for a PVC (for example, too long). \n
+ An existing PVC with that name that is not owned by the
+ pod will *not* be used for the pod to avoid using an unrelated
+ volume by mistake. Starting the pod is then blocked until
+ the unrelated PVC is removed. If such a pre-created PVC
+ is meant to be used by the pod, the PVC has to updated
+ with an owner reference to the pod once the pod exists.
+ Normally this should not be necessary, but it may be useful
+ when manually reconstructing a broken cluster. \n This
+ field is read-only and no changes will be made by Kubernetes
+ to the PVC after it has been created. \n Required, must
+ not be nil."
+ properties:
+ metadata:
+ description: May contain labels and annotations that
+ will be copied into the PVC when creating it. No other
+ fields are allowed and will be rejected during validation.
+ type: object
+ spec:
+ description: The specification for the PersistentVolumeClaim.
+ The entire content is copied unchanged into the PVC
+ that gets created from this template. The same fields
+ as in a PersistentVolumeClaim are also valid here.
+ properties:
+ accessModes:
+ description: 'accessModes contains the desired access
+ modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+ items:
+ type: string
+ type: array
+ dataSource:
+ description: 'dataSource field can be used to specify
+ either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
+ * An existing PVC (PersistentVolumeClaim) If the
+ provisioner or an external controller can support
+ the specified data source, it will create a new
+ volume based on the contents of the specified
+ data source. If the AnyVolumeDataSource feature
+ gate is enabled, this field will always have the
+ same contents as the DataSourceRef field.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API
+ group. For any other third-party types, APIGroup
+ is required.
+ type: string
+ kind:
+ description: Kind is the type of resource being
+ referenced
+ type: string
+ name:
+ description: Name is the name of resource being
+ referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ dataSourceRef:
+ description: 'dataSourceRef specifies the object
+ from which to populate the volume with data, if
+ a non-empty volume is desired. This may be any
+ local object from a non-empty API group (non core
+ object) or a PersistentVolumeClaim object. When
+ this field is specified, volume binding will only
+ succeed if the type of the specified object matches
+ some installed volume populator or dynamic provisioner.
+ This field will replace the functionality of the
+ DataSource field and as such if both fields are
+ non-empty, they must have the same value. For
+ backwards compatibility, both fields (DataSource
+ and DataSourceRef) will be set to the same value
+ automatically if one of them is empty and the
+ other is non-empty. There are two important differences
+ between DataSource and DataSourceRef: * While
+ DataSource only allows two specific types of objects,
+ DataSourceRef allows any non-core object, as well
+ as PersistentVolumeClaim objects. * While DataSource
+ ignores disallowed values (dropping them), DataSourceRef
+ preserves all values, and generates an error if
+ a disallowed value is specified. (Beta) Using
+ this field requires the AnyVolumeDataSource feature
+ gate to be enabled.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API
+ group. For any other third-party types, APIGroup
+ is required.
+ type: string
+ kind:
+ description: Kind is the type of resource being
+ referenced
+ type: string
+ name:
+ description: Name is the name of resource being
+ referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ resources:
+ description: 'resources represents the minimum resources
+ the volume should have. If RecoverVolumeExpansionFailure
+ feature is enabled users are allowed to specify
+ resource requirements that are lower than previous
+ value but must still be higher than capacity recorded
+ in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount
+ of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum
+ amount of compute resources required. If Requests
+ is omitted for a container, it defaults to
+ Limits if that is explicitly specified, otherwise
+ to an implementation-defined value. More info:
+ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ selector:
+ description: selector is a label query over volumes
+ to consider for binding.
+ 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
+ x-kubernetes-map-type: atomic
+ storageClassName:
+ description: 'storageClassName is the name of the
+ StorageClass required by the claim. More info:
+ https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
+ type: string
+ volumeMode:
+ description: volumeMode defines what type of volume
+ is required by the claim. Value of Filesystem
+ is implied when not included in claim spec.
+ type: string
+ volumeName:
+ description: volumeName is the binding reference
+ to the PersistentVolume backing this claim.
+ type: string
+ type: object
+ required:
+ - spec
+ type: object
+ type: object
+ fc:
+ description: fc represents a Fibre Channel resource that is
+ attached to a kubelet's host machine and then exposed to the
+ pod.
+ properties:
+ fsType:
+ description: 'fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified. TODO: how do we prevent errors in the
+ filesystem from compromising the machine'
+ type: string
+ lun:
+ description: 'lun is Optional: FC target lun number'
+ format: int32
+ type: integer
+ readOnly:
+ description: 'readOnly is Optional: Defaults to false (read/write).
+ ReadOnly here will force the ReadOnly setting in VolumeMounts.'
+ type: boolean
+ targetWWNs:
+ description: 'targetWWNs is Optional: FC target worldwide
+ names (WWNs)'
+ items:
+ type: string
+ type: array
+ wwids:
+ description: 'wwids Optional: FC volume world wide identifiers
+ (wwids) Either wwids or combination of targetWWNs and
+ lun must be set, but not both simultaneously.'
+ items:
+ type: string
+ type: array
+ type: object
+ flexVolume:
+ description: flexVolume represents a generic volume resource
+ that is provisioned/attached using an exec based plugin.
+ properties:
+ driver:
+ description: driver is the name of the driver to use for
+ this volume.
+ type: string
+ fsType:
+ description: fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". The default filesystem depends
+ on FlexVolume script.
+ type: string
+ options:
+ additionalProperties:
+ type: string
+ description: 'options is Optional: this field holds extra
+ command options if any.'
+ type: object
+ readOnly:
+ description: 'readOnly is Optional: defaults to false (read/write).
+ ReadOnly here will force the ReadOnly setting in VolumeMounts.'
+ type: boolean
+ secretRef:
+ description: 'secretRef is Optional: secretRef is reference
+ to the secret object containing sensitive information
+ to pass to the plugin scripts. This may be empty if no
+ secret object is specified. If the secret object contains
+ more than one secret, all secrets are passed to the plugin
+ scripts.'
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ required:
+ - driver
+ type: object
+ flocker:
+ description: flocker represents a Flocker volume attached to
+ a kubelet's host machine. This depends on the Flocker control
+ service being running
+ properties:
+ datasetName:
+ description: datasetName is Name of the dataset stored as
+ metadata -> name on the dataset for Flocker should be
+ considered as deprecated
+ type: string
+ datasetUUID:
+ description: datasetUUID is the UUID of the dataset. This
+ is unique identifier of a Flocker dataset
+ type: string
+ type: object
+ gcePersistentDisk:
+ description: 'gcePersistentDisk represents a GCE Disk resource
+ that is attached to a kubelet''s host machine and then exposed
+ to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk'
+ properties:
+ fsType:
+ description: 'fsType is filesystem type of the volume that
+ you want to mount. Tip: Ensure that the filesystem type
+ is supported by the host operating system. Examples: "ext4",
+ "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk
+ TODO: how do we prevent errors in the filesystem from
+ compromising the machine'
+ type: string
+ partition:
+ description: 'partition is the partition in the volume that
+ you want to mount. If omitted, the default is to mount
+ by volume name. Examples: For volume /dev/sda1, you specify
+ the partition as "1". Similarly, the volume partition
+ for /dev/sda is "0" (or you can leave the property empty).
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk'
+ format: int32
+ type: integer
+ pdName:
+ description: 'pdName is unique name of the PD resource in
+ GCE. Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk'
+ type: string
+ readOnly:
+ description: 'readOnly here will force the ReadOnly setting
+ in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk'
+ type: boolean
+ required:
+ - pdName
+ type: object
+ gitRepo:
+ description: 'gitRepo represents a git repository at a particular
+ revision. DEPRECATED: GitRepo is deprecated. To provision
+ a container with a git repo, mount an EmptyDir into an InitContainer
+ that clones the repo using git, then mount the EmptyDir into
+ the Pod''s container.'
+ properties:
+ directory:
+ description: directory is the target directory name. Must
+ not contain or start with '..'. If '.' is supplied, the
+ volume directory will be the git repository. Otherwise,
+ if specified, the volume will contain the git repository
+ in the subdirectory with the given name.
+ type: string
+ repository:
+ description: repository is the URL
+ type: string
+ revision:
+ description: revision is the commit hash for the specified
+ revision.
+ type: string
+ required:
+ - repository
+ type: object
+ glusterfs:
+ description: 'glusterfs represents a Glusterfs mount on the
+ host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md'
+ properties:
+ endpoints:
+ description: 'endpoints is the endpoint name that details
+ Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod'
+ type: string
+ path:
+ description: 'path is the Glusterfs volume path. More info:
+ https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod'
+ type: string
+ readOnly:
+ description: 'readOnly here will force the Glusterfs volume
+ to be mounted with read-only permissions. Defaults to
+ false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod'
+ type: boolean
+ required:
+ - endpoints
+ - path
+ type: object
+ hostPath:
+ description: 'hostPath represents a pre-existing file or directory
+ on the host machine that is directly exposed to the container.
+ This is generally used for system agents or other privileged
+ things that are allowed to see the host machine. Most containers
+ will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath
+ --- TODO(jonesdl) We need to restrict who can use host directory
+ mounts and who can/can not mount host directories as read/write.'
+ properties:
+ path:
+ description: 'path of the directory on the host. If the
+ path is a symlink, it will follow the link to the real
+ path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath'
+ type: string
+ type:
+ description: 'type for HostPath Volume Defaults to "" More
+ info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath'
+ type: string
+ required:
+ - path
+ type: object
+ iscsi:
+ description: 'iscsi represents an ISCSI Disk resource that is
+ attached to a kubelet''s host machine and then exposed to
+ the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md'
+ properties:
+ chapAuthDiscovery:
+ description: chapAuthDiscovery defines whether support iSCSI
+ Discovery CHAP authentication
+ type: boolean
+ chapAuthSession:
+ description: chapAuthSession defines whether support iSCSI
+ Session CHAP authentication
+ type: boolean
+ fsType:
+ description: 'fsType is the filesystem type of the volume
+ that you want to mount. Tip: Ensure that the filesystem
+ type is supported by the host operating system. Examples:
+ "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi
+ TODO: how do we prevent errors in the filesystem from
+ compromising the machine'
+ type: string
+ initiatorName:
+ description: initiatorName is the custom iSCSI Initiator
+ Name. If initiatorName is specified with iscsiInterface
+ simultaneously, new iSCSI interface : will be created for the connection.
+ type: string
+ iqn:
+ description: iqn is the target iSCSI Qualified Name.
+ type: string
+ iscsiInterface:
+ description: iscsiInterface is the interface Name that uses
+ an iSCSI transport. Defaults to 'default' (tcp).
+ type: string
+ lun:
+ description: lun represents iSCSI Target Lun number.
+ format: int32
+ type: integer
+ portals:
+ description: portals is the iSCSI Target Portal List. The
+ portal is either an IP or ip_addr:port if the port is
+ other than default (typically TCP ports 860 and 3260).
+ items:
+ type: string
+ type: array
+ readOnly:
+ description: readOnly here will force the ReadOnly setting
+ in VolumeMounts. Defaults to false.
+ type: boolean
+ secretRef:
+ description: secretRef is the CHAP Secret for iSCSI target
+ and initiator authentication
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ targetPortal:
+ description: targetPortal is iSCSI Target Portal. The Portal
+ is either an IP or ip_addr:port if the port is other than
+ default (typically TCP ports 860 and 3260).
+ type: string
+ required:
+ - iqn
+ - lun
+ - targetPortal
+ type: object
+ name:
+ description: 'name of the volume. Must be a DNS_LABEL and unique
+ within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
+ type: string
+ nfs:
+ description: 'nfs represents an NFS mount on the host that shares
+ a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs'
+ properties:
+ path:
+ description: 'path that is exported by the NFS server. More
+ info: https://kubernetes.io/docs/concepts/storage/volumes#nfs'
+ type: string
+ readOnly:
+ description: 'readOnly here will force the NFS export to
+ be mounted with read-only permissions. Defaults to false.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs'
+ type: boolean
+ server:
+ description: 'server is the hostname or IP address of the
+ NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs'
+ type: string
+ required:
+ - path
+ - server
+ type: object
+ persistentVolumeClaim:
+ description: 'persistentVolumeClaimVolumeSource represents a
+ reference to a PersistentVolumeClaim in the same namespace.
+ More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
+ properties:
+ claimName:
+ description: 'claimName is the name of a PersistentVolumeClaim
+ in the same namespace as the pod using this volume. More
+ info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
+ type: string
+ readOnly:
+ description: readOnly Will force the ReadOnly setting in
+ VolumeMounts. Default false.
+ type: boolean
+ required:
+ - claimName
+ type: object
+ photonPersistentDisk:
+ description: photonPersistentDisk represents a PhotonController
+ persistent disk attached and mounted on kubelets host machine
+ properties:
+ fsType:
+ description: fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ pdID:
+ description: pdID is the ID that identifies Photon Controller
+ persistent disk
+ type: string
+ required:
+ - pdID
+ type: object
+ portworxVolume:
+ description: portworxVolume represents a portworx volume attached
+ and mounted on kubelets host machine
+ properties:
+ fsType:
+ description: fSType represents the filesystem type to mount
+ Must be a filesystem type supported by the host operating
+ system. Ex. "ext4", "xfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ readOnly:
+ description: readOnly defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ volumeID:
+ description: volumeID uniquely identifies a Portworx volume
+ type: string
+ required:
+ - volumeID
+ type: object
+ projected:
+ description: projected items for all in one resources secrets,
+ configmaps, and downward API
+ properties:
+ defaultMode:
+ description: defaultMode are the mode bits used to set permissions
+ on created files by default. Must be an octal value between
+ 0000 and 0777 or a decimal value between 0 and 511. YAML
+ accepts both octal and decimal values, JSON requires decimal
+ values for mode bits. Directories within the path are
+ not affected by this setting. This might be in conflict
+ with other options that affect the file mode, like fsGroup,
+ and the result can be other mode bits set.
+ format: int32
+ type: integer
+ sources:
+ description: sources is the list of volume projections
+ items:
+ description: Projection that may be projected along with
+ other supported volume types
+ properties:
+ configMap:
+ description: configMap information about the configMap
+ data to project
+ properties:
+ items:
+ description: items if unspecified, each key-value
+ pair in the Data field of the referenced ConfigMap
+ will be projected into the volume as a file
+ whose name is the key and content is the value.
+ If specified, the listed keys will be projected
+ into the specified paths, and unlisted keys
+ will not be present. If a key is specified which
+ is not present in the ConfigMap, the volume
+ setup will error unless it is marked optional.
+ Paths must be relative and may not contain the
+ '..' path or start with '..'.
+ items:
+ description: Maps a string key to a path within
+ a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: 'mode is Optional: mode bits
+ used to set permissions on this file.
+ Must be an octal value between 0000 and
+ 0777 or a decimal value between 0 and
+ 511. YAML accepts both octal and decimal
+ values, JSON requires decimal values for
+ mode bits. If not specified, the volume
+ defaultMode will be used. This might be
+ in conflict with other options that affect
+ the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: path is the relative path of
+ the file to map the key to. May not be
+ an absolute path. May not contain the
+ path element '..'. May not start with
+ the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: optional specify whether the ConfigMap
+ or its keys must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ downwardAPI:
+ description: downwardAPI information about the downwardAPI
+ data to project
+ properties:
+ items:
+ description: Items is a list of DownwardAPIVolume
+ file
+ items:
+ description: DownwardAPIVolumeFile represents
+ information to create the file containing
+ the pod field
+ properties:
+ fieldRef:
+ description: 'Required: Selects a field
+ of the pod: only annotations, labels,
+ name and namespace are supported.'
+ properties:
+ apiVersion:
+ description: Version of the schema the
+ FieldPath is written in terms of,
+ defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select
+ in the specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ mode:
+ description: 'Optional: mode bits used to
+ set permissions on this file, must be
+ an octal value between 0000 and 0777 or
+ a decimal value between 0 and 511. YAML
+ accepts both octal and decimal values,
+ JSON requires decimal values for mode
+ bits. If not specified, the volume defaultMode
+ will be used. This might be in conflict
+ with other options that affect the file
+ mode, like fsGroup, and the result can
+ be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: 'Required: Path is the relative
+ path name of the file to be created. Must
+ not be absolute or contain the ''..''
+ path. Must be utf-8 encoded. The first
+ item of the relative path must not start
+ with ''..'''
+ type: string
+ resourceFieldRef:
+ description: 'Selects a resource of the
+ container: only resources limits and requests
+ (limits.cpu, limits.memory, requests.cpu
+ and requests.memory) are currently supported.'
+ properties:
+ containerName:
+ description: 'Container name: required
+ for volumes, optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format
+ of the exposed resources, defaults
+ to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to
+ select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ required:
+ - path
+ type: object
+ type: array
+ type: object
+ secret:
+ description: secret information about the secret data
+ to project
+ properties:
+ items:
+ description: items if unspecified, each key-value
+ pair in the Data field of the referenced Secret
+ will be projected into the volume as a file
+ whose name is the key and content is the value.
+ If specified, the listed keys will be projected
+ into the specified paths, and unlisted keys
+ will not be present. If a key is specified which
+ is not present in the Secret, the volume setup
+ will error unless it is marked optional. Paths
+ must be relative and may not contain the '..'
+ path or start with '..'.
+ items:
+ description: Maps a string key to a path within
+ a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: 'mode is Optional: mode bits
+ used to set permissions on this file.
+ Must be an octal value between 0000 and
+ 0777 or a decimal value between 0 and
+ 511. YAML accepts both octal and decimal
+ values, JSON requires decimal values for
+ mode bits. If not specified, the volume
+ defaultMode will be used. This might be
+ in conflict with other options that affect
+ the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: path is the relative path of
+ the file to map the key to. May not be
+ an absolute path. May not contain the
+ path element '..'. May not start with
+ the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: optional field specify whether the
+ Secret or its key must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ serviceAccountToken:
+ description: serviceAccountToken is information about
+ the serviceAccountToken data to project
+ properties:
+ audience:
+ description: audience is the intended audience
+ of the token. A recipient of a token must identify
+ itself with an identifier specified in the audience
+ of the token, and otherwise should reject the
+ token. The audience defaults to the identifier
+ of the apiserver.
+ type: string
+ expirationSeconds:
+ description: expirationSeconds is the requested
+ duration of validity of the service account
+ token. As the token approaches expiration, the
+ kubelet volume plugin will proactively rotate
+ the service account token. The kubelet will
+ start trying to rotate the token if the token
+ is older than 80 percent of its time to live
+ or if the token is older than 24 hours.Defaults
+ to 1 hour and must be at least 10 minutes.
+ format: int64
+ type: integer
+ path:
+ description: path is the path relative to the
+ mount point of the file to project the token
+ into.
+ type: string
+ required:
+ - path
+ type: object
+ type: object
+ type: array
+ type: object
+ quobyte:
+ description: quobyte represents a Quobyte mount on the host
+ that shares a pod's lifetime
+ properties:
+ group:
+ description: group to map volume access to Default is no
+ group
+ type: string
+ readOnly:
+ description: readOnly here will force the Quobyte volume
+ to be mounted with read-only permissions. Defaults to
+ false.
+ type: boolean
+ registry:
+ description: registry represents a single or multiple Quobyte
+ Registry services specified as a string as host:port pair
+ (multiple entries are separated with commas) which acts
+ as the central registry for volumes
+ type: string
+ tenant:
+ description: tenant owning the given Quobyte volume in the
+ Backend Used with dynamically provisioned Quobyte volumes,
+ value is set by the plugin
+ type: string
+ user:
+ description: user to map volume access to Defaults to serivceaccount
+ user
+ type: string
+ volume:
+ description: volume is a string that references an already
+ created Quobyte volume by name.
+ type: string
+ required:
+ - registry
+ - volume
+ type: object
+ rbd:
+ description: 'rbd represents a Rados Block Device mount on the
+ host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md'
+ properties:
+ fsType:
+ description: 'fsType is the filesystem type of the volume
+ that you want to mount. Tip: Ensure that the filesystem
+ type is supported by the host operating system. Examples:
+ "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd
+ TODO: how do we prevent errors in the filesystem from
+ compromising the machine'
+ type: string
+ image:
+ description: 'image is the rados image name. More info:
+ https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: string
+ keyring:
+ description: 'keyring is the path to key ring for RBDUser.
+ Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: string
+ monitors:
+ description: 'monitors is a collection of Ceph monitors.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ items:
+ type: string
+ type: array
+ pool:
+ description: 'pool is the rados pool name. Default is rbd.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: string
+ readOnly:
+ description: 'readOnly here will force the ReadOnly setting
+ in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: boolean
+ secretRef:
+ description: 'secretRef is name of the authentication secret
+ for RBDUser. If provided overrides keyring. Default is
+ nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ user:
+ description: 'user is the rados user name. Default is admin.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: string
+ required:
+ - image
+ - monitors
+ type: object
+ scaleIO:
+ description: scaleIO represents a ScaleIO persistent volume
+ attached and mounted on Kubernetes nodes.
+ properties:
+ fsType:
+ description: fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Default is "xfs".
+ type: string
+ gateway:
+ description: gateway is the host address of the ScaleIO
+ API Gateway.
+ type: string
+ protectionDomain:
+ description: protectionDomain is the name of the ScaleIO
+ Protection Domain for the configured storage.
+ type: string
+ readOnly:
+ description: readOnly Defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretRef:
+ description: secretRef references to the secret for ScaleIO
+ user and other sensitive information. If this is not provided,
+ Login operation will fail.
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ sslEnabled:
+ description: sslEnabled Flag enable/disable SSL communication
+ with Gateway, default false
+ type: boolean
+ storageMode:
+ description: storageMode indicates whether the storage for
+ a volume should be ThickProvisioned or ThinProvisioned.
+ Default is ThinProvisioned.
+ type: string
+ storagePool:
+ description: storagePool is the ScaleIO Storage Pool associated
+ with the protection domain.
+ type: string
+ system:
+ description: system is the name of the storage system as
+ configured in ScaleIO.
+ type: string
+ volumeName:
+ description: volumeName is the name of a volume already
+ created in the ScaleIO system that is associated with
+ this volume source.
+ type: string
+ required:
+ - gateway
+ - secretRef
+ - system
+ type: object
+ secret:
+ description: 'secret represents a secret that should populate
+ this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
+ properties:
+ defaultMode:
+ description: 'defaultMode is Optional: mode bits used to
+ set permissions on created files by default. Must be an
+ octal value between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. Defaults to
+ 0644. Directories within the path are not affected by
+ this setting. This might be in conflict with other options
+ that affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ items:
+ description: items If unspecified, each key-value pair in
+ the Data field of the referenced Secret will be projected
+ into the volume as a file whose name is the key and content
+ is the value. If specified, the listed keys will be projected
+ into the specified paths, and unlisted keys will not be
+ present. If a key is specified which is not present in
+ the Secret, the volume setup will error unless it is marked
+ optional. Paths must be relative and may not contain the
+ '..' path or start with '..'.
+ items:
+ description: Maps a string key to a path within a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: 'mode is Optional: mode bits used to
+ set permissions on this file. Must be an octal value
+ between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. If not
+ specified, the volume defaultMode will be used.
+ This might be in conflict with other options that
+ affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: path is the relative path of the file
+ to map the key to. May not be an absolute path.
+ May not contain the path element '..'. May not start
+ with the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ optional:
+ description: optional field specify whether the Secret or
+ its keys must be defined
+ type: boolean
+ secretName:
+ description: 'secretName is the name of the secret in the
+ pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
+ type: string
+ type: object
+ storageos:
+ description: storageOS represents a StorageOS volume attached
+ and mounted on Kubernetes nodes.
+ properties:
+ fsType:
+ description: fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ readOnly:
+ description: readOnly defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretRef:
+ description: secretRef specifies the secret to use for obtaining
+ the StorageOS API credentials. If not specified, default
+ values will be attempted.
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ volumeName:
+ description: volumeName is the human-readable name of the
+ StorageOS volume. Volume names are only unique within
+ a namespace.
+ type: string
+ volumeNamespace:
+ description: volumeNamespace specifies the scope of the
+ volume within StorageOS. If no namespace is specified
+ then the Pod's namespace will be used. This allows the
+ Kubernetes name scoping to be mirrored within StorageOS
+ for tighter integration. Set VolumeName to any name to
+ override the default behaviour. Set to "default" if you
+ are not using namespaces within StorageOS. Namespaces
+ that do not pre-exist within StorageOS will be created.
+ type: string
+ type: object
+ vsphereVolume:
+ description: vsphereVolume represents a vSphere volume attached
+ and mounted on kubelets host machine
+ properties:
+ fsType:
+ description: fsType is filesystem type to mount. Must be
+ a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ storagePolicyID:
+ description: storagePolicyID is the storage Policy Based
+ Management (SPBM) profile ID associated with the StoragePolicyName.
+ type: string
+ storagePolicyName:
+ description: storagePolicyName is the storage Policy Based
+ Management (SPBM) profile name.
+ type: string
+ volumePath:
+ description: volumePath is the path that identifies vSphere
+ volume vmdk
+ type: string
+ required:
+ - volumePath
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ walCompression:
+ description: Enable compression of the write-ahead log using Snappy.
+ This flag is only available in versions of Prometheus >= 2.11.0.
+ type: boolean
+ web:
+ description: Defines the web command line flags when starting Prometheus.
+ properties:
+ httpConfig:
+ description: Defines HTTP parameters for web server.
+ properties:
+ headers:
+ description: List of headers that can be added to HTTP responses.
+ properties:
+ contentSecurityPolicy:
+ description: Set the Content-Security-Policy header to
+ HTTP responses. Unset if blank.
+ type: string
+ strictTransportSecurity:
+ description: Set the Strict-Transport-Security header
+ to HTTP responses. Unset if blank. Please make sure
+ that you use this with care as this header might force
+ browsers to load Prometheus and the other applications
+ hosted on the same domain and subdomains over HTTPS.
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
+ type: string
+ xContentTypeOptions:
+ description: Set the X-Content-Type-Options header to
+ HTTP responses. Unset if blank. Accepted value is nosniff.
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
+ enum:
+ - ""
+ - NoSniff
+ type: string
+ xFrameOptions:
+ description: Set the X-Frame-Options header to HTTP responses.
+ Unset if blank. Accepted values are deny and sameorigin.
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
+ enum:
+ - ""
+ - Deny
+ - SameOrigin
+ type: string
+ xXSSProtection:
+ description: Set the X-XSS-Protection header to all responses.
+ Unset if blank. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
+ type: string
+ type: object
+ http2:
+ description: Enable HTTP/2 support. Note that HTTP/2 is only
+ supported with TLS. When TLSConfig is not configured, HTTP/2
+ will be disabled. Whenever the value of the field changes,
+ a rolling update will be triggered.
+ type: boolean
+ type: object
+ pageTitle:
+ description: The prometheus web page title
+ type: string
+ tlsConfig:
+ description: Defines the TLS parameters for HTTPS.
+ properties:
+ cert:
+ description: Contains the TLS certificate for the server.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ cipherSuites:
+ description: 'List of supported cipher suites for TLS versions
+ up to TLS 1.2. If empty, Go default cipher suites are used.
+ Available cipher suites are documented in the go documentation:
+ https://golang.org/pkg/crypto/tls/#pkg-constants'
+ items:
+ type: string
+ type: array
+ client_ca:
+ description: Contains the CA certificate for client certificate
+ authentication to the server.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientAuthType:
+ description: 'Server policy for client authentication. Maps
+ to ClientAuth Policies. For more detail on clientAuth options:
+ https://golang.org/pkg/crypto/tls/#ClientAuthType'
+ type: string
+ curvePreferences:
+ description: 'Elliptic curves that will be used in an ECDHE
+ handshake, in preference order. Available curves are documented
+ in the go documentation: https://golang.org/pkg/crypto/tls/#CurveID'
+ items:
+ type: string
+ type: array
+ keySecret:
+ description: Secret containing the TLS key for the server.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ maxVersion:
+ description: Maximum TLS version that is acceptable. Defaults
+ to TLS13.
+ type: string
+ minVersion:
+ description: Minimum TLS version that is acceptable. Defaults
+ to TLS12.
+ type: string
+ preferServerCipherSuites:
+ description: Controls whether the server selects the client's
+ most preferred cipher suite, or the server's most preferred
+ cipher suite. If true then the server's preference, as expressed
+ in the order of elements in cipherSuites, is used.
+ type: boolean
+ required:
+ - cert
+ - keySecret
+ type: object
+ type: object
+ type: object
+ status:
+ description: 'Most recent observed status of the Prometheus cluster. Read-only.
+ More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status'
+ properties:
+ availableReplicas:
+ description: Total number of available pods (ready for at least minReadySeconds)
+ targeted by this Prometheus deployment.
+ format: int32
+ type: integer
+ conditions:
+ description: The current state of the Prometheus deployment.
+ items:
+ description: PrometheusCondition represents the state of the resources
+ associated with the Prometheus resource.
+ properties:
+ lastTransitionTime:
+ description: lastTransitionTime is the time of the last update
+ to the current status property.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details for the
+ condition's last transition.
+ type: string
+ reason:
+ description: Reason for the condition's last transition.
+ type: string
+ status:
+ description: status of the condition.
+ type: string
+ type:
+ description: Type of the condition being reported.
+ type: string
+ required:
+ - lastTransitionTime
+ - status
+ - type
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - type
+ x-kubernetes-list-type: map
+ paused:
+ description: Represents whether any actions on the underlying managed
+ objects are being performed. Only delete actions will be performed.
+ type: boolean
+ replicas:
+ description: Total number of non-terminated pods targeted by this
+ Prometheus deployment (their labels match the selector).
+ format: int32
+ type: integer
+ shardStatuses:
+ description: The list has one entry per shard. Each entry provides
+ a summary of the shard status.
+ items:
+ properties:
+ availableReplicas:
+ description: Total number of available pods (ready for at least
+ minReadySeconds) targeted by this shard.
+ format: int32
+ type: integer
+ replicas:
+ description: Total number of pods targeted by this shard.
+ format: int32
+ type: integer
+ shardID:
+ description: Identifier of the shard.
+ type: string
+ unavailableReplicas:
+ description: Total number of unavailable pods targeted by this
+ shard.
+ format: int32
+ type: integer
+ updatedReplicas:
+ description: Total number of non-terminated pods targeted by
+ this shard that have the desired spec.
+ format: int32
+ type: integer
+ required:
+ - availableReplicas
+ - replicas
+ - shardID
+ - unavailableReplicas
+ - updatedReplicas
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - shardID
+ x-kubernetes-list-type: map
+ unavailableReplicas:
+ description: Total number of unavailable pods targeted by this Prometheus
+ deployment.
+ format: int32
+ type: integer
+ updatedReplicas:
+ description: Total number of non-terminated pods targeted by this
+ Prometheus deployment that have the desired version spec.
+ format: int32
+ type: integer
+ required:
+ - availableReplicas
+ - paused
+ - replicas
+ - unavailableReplicas
+ - updatedReplicas
+ type: object
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/kube-prometheus-stack/crds/crd-prometheusrules.yaml b/kube-prometheus-stack/crds/crd-prometheusrules.yaml
new file mode 100644
index 00000000..59b04015
--- /dev/null
+++ b/kube-prometheus-stack/crds/crd-prometheusrules.yaml
@@ -0,0 +1,98 @@
+# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.2/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.9.2
+ creationTimestamp: null
+ name: prometheusrules.monitoring.coreos.com
+spec:
+ group: monitoring.coreos.com
+ names:
+ categories:
+ - prometheus-operator
+ kind: PrometheusRule
+ listKind: PrometheusRuleList
+ plural: prometheusrules
+ shortNames:
+ - promrule
+ singular: prometheusrule
+ scope: Namespaced
+ versions:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description: PrometheusRule defines recording and alerting rules for a Prometheus
+ instance
+ 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: Specification of desired alerting rule definitions for Prometheus.
+ properties:
+ groups:
+ description: Content of Prometheus rule file
+ items:
+ description: 'RuleGroup is a list of sequentially evaluated recording
+ and alerting rules. Note: PartialResponseStrategy is only used
+ by ThanosRuler and will be ignored by Prometheus instances. Valid
+ values for this field are ''warn'' or ''abort''. More info: https://github.com/thanos-io/thanos/blob/main/docs/components/rule.md#partial-response'
+ properties:
+ interval:
+ type: string
+ name:
+ type: string
+ partial_response_strategy:
+ type: string
+ rules:
+ items:
+ description: 'Rule describes an alerting or recording rule
+ See Prometheus documentation: [alerting](https://www.prometheus.io/docs/prometheus/latest/configuration/alerting_rules/)
+ or [recording](https://www.prometheus.io/docs/prometheus/latest/configuration/recording_rules/#recording-rules)
+ rule'
+ properties:
+ alert:
+ type: string
+ annotations:
+ additionalProperties:
+ type: string
+ type: object
+ expr:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ for:
+ type: string
+ labels:
+ additionalProperties:
+ type: string
+ type: object
+ record:
+ type: string
+ required:
+ - expr
+ type: object
+ type: array
+ required:
+ - name
+ - rules
+ type: object
+ type: array
+ type: object
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
diff --git a/kube-prometheus-stack/crds/crd-servicemonitors.yaml b/kube-prometheus-stack/crds/crd-servicemonitors.yaml
new file mode 100644
index 00000000..3edbf032
--- /dev/null
+++ b/kube-prometheus-stack/crds/crd-servicemonitors.yaml
@@ -0,0 +1,684 @@
+# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.2/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.9.2
+ creationTimestamp: null
+ name: servicemonitors.monitoring.coreos.com
+spec:
+ group: monitoring.coreos.com
+ names:
+ categories:
+ - prometheus-operator
+ kind: ServiceMonitor
+ listKind: ServiceMonitorList
+ plural: servicemonitors
+ shortNames:
+ - smon
+ singular: servicemonitor
+ scope: Namespaced
+ versions:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description: ServiceMonitor defines monitoring for a set of 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: Specification of desired Service selection for target discovery
+ by Prometheus.
+ properties:
+ endpoints:
+ description: A list of endpoints allowed as part of this ServiceMonitor.
+ items:
+ description: Endpoint defines a scrapeable endpoint serving Prometheus
+ metrics.
+ properties:
+ authorization:
+ description: Authorization section for this endpoint
+ properties:
+ credentials:
+ description: The secret's key that contains the credentials
+ of the request
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type:
+ description: Set the authentication type. Defaults to Bearer,
+ Basic will cause an error
+ type: string
+ type: object
+ basicAuth:
+ description: 'BasicAuth allow an endpoint to authenticate over
+ basic authentication More info: https://prometheus.io/docs/operating/configuration/#endpoints'
+ properties:
+ password:
+ description: The secret in the service monitor namespace
+ that contains the password for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: The secret in the service monitor namespace
+ that contains the username for authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ bearerTokenFile:
+ description: File to read bearer token for scraping targets.
+ type: string
+ bearerTokenSecret:
+ description: Secret to mount to read bearer token for scraping
+ targets. The secret needs to be in the same namespace as the
+ service monitor and accessible by the Prometheus Operator.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ enableHttp2:
+ description: Whether to enable HTTP2.
+ type: boolean
+ followRedirects:
+ description: FollowRedirects configures whether scrape requests
+ follow HTTP 3xx redirects.
+ type: boolean
+ honorLabels:
+ description: HonorLabels chooses the metric's labels on collisions
+ with target labels.
+ type: boolean
+ honorTimestamps:
+ description: HonorTimestamps controls whether Prometheus respects
+ the timestamps present in scraped data.
+ type: boolean
+ interval:
+ description: Interval at which metrics should be scraped If
+ not specified Prometheus' global scrape interval is used.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ metricRelabelings:
+ description: MetricRelabelConfigs to apply to samples before
+ ingestion.
+ items:
+ description: 'RelabelConfig allows dynamic rewriting of the
+ label set, being applied to samples before ingestion. It
+ defines ``-section of Prometheus
+ configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
+ properties:
+ action:
+ default: replace
+ description: Action to perform based on regex matching.
+ Default is 'replace'. uppercase and lowercase actions
+ require Prometheus >= 2.36.
+ enum:
+ - replace
+ - Replace
+ - keep
+ - Keep
+ - drop
+ - Drop
+ - hashmod
+ - HashMod
+ - labelmap
+ - LabelMap
+ - labeldrop
+ - LabelDrop
+ - labelkeep
+ - LabelKeep
+ - lowercase
+ - Lowercase
+ - uppercase
+ - Uppercase
+ type: string
+ modulus:
+ description: Modulus to take of the hash of the source
+ label values.
+ format: int64
+ type: integer
+ regex:
+ description: Regular expression against which the extracted
+ value is matched. Default is '(.*)'
+ type: string
+ replacement:
+ description: Replacement value against which a regex replace
+ is performed if the regular expression matches. Regex
+ capture groups are available. Default is '$1'
+ type: string
+ separator:
+ description: Separator placed between concatenated source
+ label values. default is ';'.
+ type: string
+ sourceLabels:
+ description: The source labels select values from existing
+ labels. Their content is concatenated using the configured
+ separator and matched against the configured regular
+ expression for the replace, keep, and drop actions.
+ items:
+ description: LabelName is a valid Prometheus label name
+ which may only contain ASCII letters, numbers, as
+ well as underscores.
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ type: string
+ type: array
+ targetLabel:
+ description: Label to which the resulting value is written
+ in a replace action. It is mandatory for replace actions.
+ Regex capture groups are available.
+ type: string
+ type: object
+ type: array
+ oauth2:
+ description: OAuth2 for the URL. Only valid in Prometheus versions
+ 2.27.0 and newer.
+ properties:
+ clientId:
+ description: The secret or configmap containing the OAuth2
+ client id
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ clientSecret:
+ description: The secret containing the OAuth2 client secret
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ endpointParams:
+ additionalProperties:
+ type: string
+ description: Parameters to append to the token URL
+ type: object
+ scopes:
+ description: OAuth2 scopes used for the token request
+ items:
+ type: string
+ type: array
+ tokenUrl:
+ description: The URL to fetch the token from
+ minLength: 1
+ type: string
+ required:
+ - clientId
+ - clientSecret
+ - tokenUrl
+ type: object
+ params:
+ additionalProperties:
+ items:
+ type: string
+ type: array
+ description: Optional HTTP URL parameters
+ type: object
+ path:
+ description: HTTP path to scrape for metrics. If empty, Prometheus
+ uses the default value (e.g. `/metrics`).
+ type: string
+ port:
+ description: Name of the service port this endpoint refers to.
+ Mutually exclusive with targetPort.
+ type: string
+ proxyUrl:
+ description: ProxyURL eg http://proxyserver:2195 Directs scrapes
+ to proxy through this endpoint.
+ type: string
+ relabelings:
+ description: 'RelabelConfigs to apply to samples before scraping.
+ Prometheus Operator automatically adds relabelings for a few
+ standard Kubernetes fields. The original scrape job''s name
+ is available via the `__tmp_prometheus_job_name` label. More
+ info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config'
+ items:
+ description: 'RelabelConfig allows dynamic rewriting of the
+ label set, being applied to samples before ingestion. It
+ defines ``-section of Prometheus
+ configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
+ properties:
+ action:
+ default: replace
+ description: Action to perform based on regex matching.
+ Default is 'replace'. uppercase and lowercase actions
+ require Prometheus >= 2.36.
+ enum:
+ - replace
+ - Replace
+ - keep
+ - Keep
+ - drop
+ - Drop
+ - hashmod
+ - HashMod
+ - labelmap
+ - LabelMap
+ - labeldrop
+ - LabelDrop
+ - labelkeep
+ - LabelKeep
+ - lowercase
+ - Lowercase
+ - uppercase
+ - Uppercase
+ type: string
+ modulus:
+ description: Modulus to take of the hash of the source
+ label values.
+ format: int64
+ type: integer
+ regex:
+ description: Regular expression against which the extracted
+ value is matched. Default is '(.*)'
+ type: string
+ replacement:
+ description: Replacement value against which a regex replace
+ is performed if the regular expression matches. Regex
+ capture groups are available. Default is '$1'
+ type: string
+ separator:
+ description: Separator placed between concatenated source
+ label values. default is ';'.
+ type: string
+ sourceLabels:
+ description: The source labels select values from existing
+ labels. Their content is concatenated using the configured
+ separator and matched against the configured regular
+ expression for the replace, keep, and drop actions.
+ items:
+ description: LabelName is a valid Prometheus label name
+ which may only contain ASCII letters, numbers, as
+ well as underscores.
+ pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
+ type: string
+ type: array
+ targetLabel:
+ description: Label to which the resulting value is written
+ in a replace action. It is mandatory for replace actions.
+ Regex capture groups are available.
+ type: string
+ type: object
+ type: array
+ scheme:
+ description: HTTP scheme to use for scraping.
+ type: string
+ scrapeTimeout:
+ description: Timeout after which the scrape is ended If not
+ specified, the Prometheus global scrape timeout is used unless
+ it is less than `Interval` in which the latter is used.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ targetPort:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the target port of the Pod behind
+ the Service, the port must be specified with container port
+ property. Mutually exclusive with port.
+ x-kubernetes-int-or-string: true
+ tlsConfig:
+ description: TLS configuration to use when scraping the endpoint
+ properties:
+ ca:
+ description: Struct containing the CA cert to use for the
+ targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ caFile:
+ description: Path to the CA cert in the Prometheus container
+ to use for the targets.
+ type: string
+ cert:
+ description: Struct containing the client cert file for
+ the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the
+ targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ certFile:
+ description: Path to the client cert file in the Prometheus
+ container for the targets.
+ type: string
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keyFile:
+ description: Path to the client key file in the Prometheus
+ container for the targets.
+ type: string
+ keySecret:
+ description: Secret containing the client key file for the
+ targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the targets.
+ type: string
+ type: object
+ type: object
+ type: array
+ jobLabel:
+ description: "JobLabel selects the label from the associated Kubernetes
+ service which will be used as the `job` label for all metrics. \n
+ For example: If in `ServiceMonitor.spec.jobLabel: foo` and in `Service.metadata.labels.foo:
+ bar`, then the `job=\"bar\"` label is added to all metrics. \n If
+ the value of this field is empty or if the label doesn't exist for
+ the given Service, the `job` label of the metrics defaults to the
+ name of the Kubernetes Service."
+ type: string
+ labelLimit:
+ description: Per-scrape limit on number of labels that will be accepted
+ for a sample. Only valid in Prometheus versions 2.27.0 and newer.
+ format: int64
+ type: integer
+ labelNameLengthLimit:
+ description: Per-scrape limit on length of labels name that will be
+ accepted for a sample. Only valid in Prometheus versions 2.27.0
+ and newer.
+ format: int64
+ type: integer
+ labelValueLengthLimit:
+ description: Per-scrape limit on length of labels value that will
+ be accepted for a sample. Only valid in Prometheus versions 2.27.0
+ and newer.
+ format: int64
+ type: integer
+ namespaceSelector:
+ description: Selector to select which namespaces the Kubernetes Endpoints
+ objects are discovered from.
+ properties:
+ any:
+ description: Boolean describing whether all namespaces are selected
+ in contrast to a list restricting them.
+ type: boolean
+ matchNames:
+ description: List of namespace names to select from.
+ items:
+ type: string
+ type: array
+ type: object
+ podTargetLabels:
+ description: PodTargetLabels transfers labels on the Kubernetes `Pod`
+ onto the created metrics.
+ items:
+ type: string
+ type: array
+ sampleLimit:
+ description: SampleLimit defines per-scrape limit on number of scraped
+ samples that will be accepted.
+ format: int64
+ type: integer
+ selector:
+ description: Selector to select Endpoints 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
+ x-kubernetes-map-type: atomic
+ targetLabels:
+ description: TargetLabels transfers labels from the Kubernetes `Service`
+ onto the created metrics.
+ items:
+ type: string
+ type: array
+ targetLimit:
+ description: TargetLimit defines a limit on the number of scraped
+ targets that will be accepted.
+ format: int64
+ type: integer
+ required:
+ - endpoints
+ - selector
+ type: object
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
diff --git a/kube-prometheus-stack/crds/crd-thanosrulers.yaml b/kube-prometheus-stack/crds/crd-thanosrulers.yaml
new file mode 100644
index 00000000..ec91fb4a
--- /dev/null
+++ b/kube-prometheus-stack/crds/crd-thanosrulers.yaml
@@ -0,0 +1,6431 @@
+# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.2/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.9.2
+ creationTimestamp: null
+ name: thanosrulers.monitoring.coreos.com
+spec:
+ group: monitoring.coreos.com
+ names:
+ categories:
+ - prometheus-operator
+ kind: ThanosRuler
+ listKind: ThanosRulerList
+ plural: thanosrulers
+ shortNames:
+ - ruler
+ singular: thanosruler
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - description: The desired replicas number of Thanos Rulers
+ jsonPath: .spec.replicas
+ name: Replicas
+ type: integer
+ - jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1
+ schema:
+ openAPIV3Schema:
+ description: ThanosRuler defines a ThanosRuler deployment.
+ 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: 'Specification of the desired behavior of the ThanosRuler
+ cluster. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status'
+ properties:
+ affinity:
+ description: If specified, the pod's scheduling constraints.
+ properties:
+ nodeAffinity:
+ description: Describes node affinity scheduling rules for the
+ pod.
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: The scheduler will prefer to schedule pods to
+ nodes that satisfy the affinity expressions specified by
+ this field, but it may choose a node that violates one or
+ more of the expressions. The node that is most preferred
+ is the one with the greatest sum of weights, i.e. for each
+ node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions,
+ etc.), compute a sum by iterating through the elements of
+ this field and adding "weight" to the sum if the node matches
+ the corresponding matchExpressions; the node(s) with the
+ highest sum are the most preferred.
+ items:
+ description: An empty preferred scheduling term matches
+ all objects with implicit weight 0 (i.e. it's a no-op).
+ A null preferred scheduling term matches no objects (i.e.
+ is also a no-op).
+ properties:
+ preference:
+ description: A node selector term, associated with the
+ corresponding weight.
+ properties:
+ matchExpressions:
+ description: A list of node selector requirements
+ by node's labels.
+ items:
+ description: A node selector requirement is a
+ selector that contains values, a key, and an
+ operator that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: Represents a key's relationship
+ to a set of values. Valid operators are
+ In, NotIn, Exists, DoesNotExist. Gt, and
+ Lt.
+ type: string
+ values:
+ description: 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. If the operator is Gt or
+ Lt, the values array must have a single
+ element, which will be interpreted as an
+ integer. This array is replaced during a
+ strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchFields:
+ description: A list of node selector requirements
+ by node's fields.
+ items:
+ description: A node selector requirement is a
+ selector that contains values, a key, and an
+ operator that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: Represents a key's relationship
+ to a set of values. Valid operators are
+ In, NotIn, Exists, DoesNotExist. Gt, and
+ Lt.
+ type: string
+ values:
+ description: 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. If the operator is Gt or
+ Lt, the values array must have a single
+ element, which will be interpreted as an
+ integer. This array is replaced during a
+ strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ type: object
+ x-kubernetes-map-type: atomic
+ weight:
+ description: Weight associated with matching the corresponding
+ nodeSelectorTerm, in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - preference
+ - weight
+ type: object
+ type: array
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: If the affinity requirements specified by this
+ field are not met at scheduling time, the pod will not be
+ scheduled onto the node. If the affinity requirements specified
+ by this field cease to be met at some point during pod execution
+ (e.g. due to an update), the system may or may not try to
+ eventually evict the pod from its node.
+ properties:
+ nodeSelectorTerms:
+ description: Required. A list of node selector terms.
+ The terms are ORed.
+ items:
+ description: A null or empty node selector term matches
+ no objects. The requirements of them are ANDed. The
+ TopologySelectorTerm type implements a subset of the
+ NodeSelectorTerm.
+ properties:
+ matchExpressions:
+ description: A list of node selector requirements
+ by node's labels.
+ items:
+ description: A node selector requirement is a
+ selector that contains values, a key, and an
+ operator that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: Represents a key's relationship
+ to a set of values. Valid operators are
+ In, NotIn, Exists, DoesNotExist. Gt, and
+ Lt.
+ type: string
+ values:
+ description: 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. If the operator is Gt or
+ Lt, the values array must have a single
+ element, which will be interpreted as an
+ integer. This array is replaced during a
+ strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ matchFields:
+ description: A list of node selector requirements
+ by node's fields.
+ items:
+ description: A node selector requirement is a
+ selector that contains values, a key, and an
+ operator that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: Represents a key's relationship
+ to a set of values. Valid operators are
+ In, NotIn, Exists, DoesNotExist. Gt, and
+ Lt.
+ type: string
+ values:
+ description: 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. If the operator is Gt or
+ Lt, the values array must have a single
+ element, which will be interpreted as an
+ integer. This array is replaced during a
+ strategic merge patch.
+ items:
+ type: string
+ type: array
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ required:
+ - nodeSelectorTerms
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ podAffinity:
+ description: Describes pod affinity scheduling rules (e.g. co-locate
+ this pod in the same node, zone, etc. as some other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: The scheduler will prefer to schedule pods to
+ nodes that satisfy the affinity expressions specified by
+ this field, but it may choose a node that violates one or
+ more of the expressions. The node that is most preferred
+ is the one with the greatest sum of weights, i.e. for each
+ node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions,
+ etc.), compute a sum by iterating through the elements of
+ this field and adding "weight" to the sum if the node has
+ pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched WeightedPodAffinityTerm
+ fields are added per-node to find the most preferred node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term, associated
+ with the corresponding weight.
+ properties:
+ labelSelector:
+ description: A label query over a set of resources,
+ in this case pods.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaceSelector:
+ description: A label query over the set of namespaces
+ that the term applies to. The term is applied
+ to the union of the namespaces selected by this
+ field and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list
+ means "this pod's namespace". An empty selector
+ ({}) matches all namespaces.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: namespaces specifies a static list
+ of namespace names that the term applies to. The
+ term is applied to the union of the namespaces
+ listed in this field and the ones selected by
+ namespaceSelector. null or empty namespaces list
+ and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ topologyKey:
+ description: This pod should be co-located (affinity)
+ or not co-located (anti-affinity) with the pods
+ matching the labelSelector in the specified namespaces,
+ where co-located is defined as running on a node
+ whose value of the label with key topologyKey
+ matches that of any node on which any of the selected
+ pods is running. Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: weight associated with matching the corresponding
+ podAffinityTerm, in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: If the affinity requirements specified by this
+ field are not met at scheduling time, the pod will not be
+ scheduled onto the node. If the affinity requirements specified
+ by this field cease to be met at some point during pod execution
+ (e.g. due to a pod label update), the system may or may
+ not try to eventually evict the pod from its node. When
+ there are multiple elements, the lists of nodes corresponding
+ to each podAffinityTerm are intersected, i.e. all terms
+ must be satisfied.
+ items:
+ description: Defines a set of pods (namely those matching
+ the labelSelector relative to the given namespace(s))
+ that this pod should be co-located (affinity) or not co-located
+ (anti-affinity) with, where co-located is defined as running
+ on a node whose value of the label with key
+ matches that of any node on which a pod of the set of
+ pods is running
+ properties:
+ labelSelector:
+ description: A label query over a set of resources,
+ in this case pods.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaceSelector:
+ description: A label query over the set of namespaces
+ that the term applies to. The term is applied to the
+ union of the namespaces selected by this field and
+ the ones listed in the namespaces field. null selector
+ and null or empty namespaces list means "this pod's
+ namespace". An empty selector ({}) matches all namespaces.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: namespaces specifies a static list of namespace
+ names that the term applies to. The term is applied
+ to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector. null or
+ empty namespaces list and null namespaceSelector means
+ "this pod's namespace".
+ items:
+ type: string
+ type: array
+ topologyKey:
+ description: This pod should be co-located (affinity)
+ or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where
+ co-located is defined as running on a node whose value
+ of the label with key topologyKey matches that of
+ any node on which any of the selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ type: object
+ podAntiAffinity:
+ description: Describes pod anti-affinity scheduling rules (e.g.
+ avoid putting this pod in the same node, zone, etc. as some
+ other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: The scheduler will prefer to schedule pods to
+ nodes that satisfy the anti-affinity expressions specified
+ by this field, but it may choose a node that violates one
+ or more of the expressions. The node that is most preferred
+ is the one with the greatest sum of weights, i.e. for each
+ node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling anti-affinity expressions,
+ etc.), compute a sum by iterating through the elements of
+ this field and adding "weight" to the sum if the node has
+ pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched WeightedPodAffinityTerm
+ fields are added per-node to find the most preferred node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term, associated
+ with the corresponding weight.
+ properties:
+ labelSelector:
+ description: A label query over a set of resources,
+ in this case pods.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaceSelector:
+ description: A label query over the set of namespaces
+ that the term applies to. The term is applied
+ to the union of the namespaces selected by this
+ field and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list
+ means "this pod's namespace". An empty selector
+ ({}) matches all namespaces.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: namespaces specifies a static list
+ of namespace names that the term applies to. The
+ term is applied to the union of the namespaces
+ listed in this field and the ones selected by
+ namespaceSelector. null or empty namespaces list
+ and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ topologyKey:
+ description: This pod should be co-located (affinity)
+ or not co-located (anti-affinity) with the pods
+ matching the labelSelector in the specified namespaces,
+ where co-located is defined as running on a node
+ whose value of the label with key topologyKey
+ matches that of any node on which any of the selected
+ pods is running. Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: weight associated with matching the corresponding
+ podAffinityTerm, in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: If the anti-affinity requirements specified by
+ this field are not met at scheduling time, the pod will
+ not be scheduled onto the node. If the anti-affinity requirements
+ specified by this field cease to be met at some point during
+ pod execution (e.g. due to a pod label update), the system
+ may or may not try to eventually evict the pod from its
+ node. When there are multiple elements, the lists of nodes
+ corresponding to each podAffinityTerm are intersected, i.e.
+ all terms must be satisfied.
+ items:
+ description: Defines a set of pods (namely those matching
+ the labelSelector relative to the given namespace(s))
+ that this pod should be co-located (affinity) or not co-located
+ (anti-affinity) with, where co-located is defined as running
+ on a node whose value of the label with key
+ matches that of any node on which a pod of the set of
+ pods is running
+ properties:
+ labelSelector:
+ description: A label query over a set of resources,
+ in this case pods.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaceSelector:
+ description: A label query over the set of namespaces
+ that the term applies to. The term is applied to the
+ union of the namespaces selected by this field and
+ the ones listed in the namespaces field. null selector
+ and null or empty namespaces list means "this pod's
+ namespace". An empty selector ({}) matches all namespaces.
+ 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
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: namespaces specifies a static list of namespace
+ names that the term applies to. The term is applied
+ to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector. null or
+ empty namespaces list and null namespaceSelector means
+ "this pod's namespace".
+ items:
+ type: string
+ type: array
+ topologyKey:
+ description: This pod should be co-located (affinity)
+ or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where
+ co-located is defined as running on a node whose value
+ of the label with key topologyKey matches that of
+ any node on which any of the selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ type: object
+ type: object
+ alertDropLabels:
+ description: AlertDropLabels configure the label names which should
+ be dropped in ThanosRuler alerts. The replica label `thanos_ruler_replica`
+ will always be dropped in alerts.
+ items:
+ type: string
+ type: array
+ alertQueryUrl:
+ description: The external Query URL the Thanos Ruler will set in the
+ 'Source' field of all alerts. Maps to the '--alert.query-url' CLI
+ arg.
+ type: string
+ alertRelabelConfigFile:
+ description: AlertRelabelConfigFile specifies the path of the alert
+ relabeling configuration file. When used alongside with AlertRelabelConfigs,
+ alertRelabelConfigFile takes precedence.
+ type: string
+ alertRelabelConfigs:
+ description: 'AlertRelabelConfigs configures alert relabeling in ThanosRuler.
+ Alert relabel configurations must have the form as specified in
+ the official Prometheus documentation: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#alert_relabel_configs
+ Alternative to AlertRelabelConfigFile, and lower order priority.'
+ properties:
+ key:
+ description: The key of the secret to select from. Must be a
+ valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ alertmanagersConfig:
+ description: Define configuration for connecting to alertmanager. Only
+ available with thanos v0.10.0 and higher. Maps to the `alertmanagers.config`
+ arg.
+ properties:
+ key:
+ description: The key of the secret to select from. Must be a
+ valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ alertmanagersUrl:
+ description: 'Define URLs to send alerts to Alertmanager. For Thanos
+ v0.10.0 and higher, AlertManagersConfig should be used instead. Note:
+ this field will be ignored if AlertManagersConfig is specified.
+ Maps to the `alertmanagers.url` arg.'
+ items:
+ type: string
+ type: array
+ containers:
+ description: 'Containers allows injecting additional containers or
+ modifying operator generated containers. This can be used to allow
+ adding an authentication proxy to a ThanosRuler pod or to change
+ the behavior of an operator generated container. Containers described
+ here modify an operator generated container if they share the same
+ name and modifications are done via a strategic merge patch. The
+ current container names are: `thanos-ruler` and `config-reloader`.
+ Overriding containers is entirely outside the scope of what the
+ maintainers will support and by doing so, you accept that this behaviour
+ may break at any time without notice.'
+ items:
+ description: A single application container that you want to run
+ within a pod.
+ properties:
+ args:
+ description: 'Arguments to the entrypoint. The container image''s
+ CMD is used if this is not provided. Variable references $(VAR_NAME)
+ are expanded using the container''s environment. If a variable
+ cannot be resolved, the reference in the input string will
+ be unchanged. Double $$ are reduced to a single $, which allows
+ for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
+ produce the string literal "$(VAR_NAME)". Escaped references
+ will never be expanded, regardless of whether the variable
+ exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
+ items:
+ type: string
+ type: array
+ command:
+ description: 'Entrypoint array. Not executed within a shell.
+ The container image''s ENTRYPOINT is used if this is not provided.
+ Variable references $(VAR_NAME) are expanded using the container''s
+ environment. If a variable cannot be resolved, the reference
+ in the input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME) syntax:
+ i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
+ Escaped references will never be expanded, regardless of whether
+ the variable exists or not. Cannot be updated. More info:
+ https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
+ items:
+ type: string
+ type: array
+ env:
+ description: List of environment variables to set in the container.
+ Cannot be updated.
+ items:
+ description: EnvVar represents an environment variable present
+ in a Container.
+ properties:
+ name:
+ description: Name of the environment variable. Must be
+ a C_IDENTIFIER.
+ type: string
+ value:
+ description: 'Variable references $(VAR_NAME) are expanded
+ using the previously defined environment variables in
+ the container and any service environment variables.
+ If a variable cannot be resolved, the reference in the
+ input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME)
+ syntax: i.e. "$$(VAR_NAME)" will produce the string
+ literal "$(VAR_NAME)". Escaped references will never
+ be expanded, regardless of whether the variable exists
+ or not. Defaults to "".'
+ type: string
+ valueFrom:
+ description: Source for the environment variable's value.
+ Cannot be used if value is not empty.
+ properties:
+ configMapKeyRef:
+ description: Selects a key of a ConfigMap.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ fieldRef:
+ description: 'Selects a field of the pod: supports
+ metadata.name, metadata.namespace, `metadata.labels['''']`,
+ `metadata.annotations['''']`, spec.nodeName,
+ spec.serviceAccountName, status.hostIP, status.podIP,
+ status.podIPs.'
+ properties:
+ apiVersion:
+ description: Version of the schema the FieldPath
+ is written in terms of, defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select in the
+ specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ resourceFieldRef:
+ description: 'Selects a resource of the container:
+ only resources limits and requests (limits.cpu,
+ limits.memory, limits.ephemeral-storage, requests.cpu,
+ requests.memory and requests.ephemeral-storage)
+ are currently supported.'
+ properties:
+ containerName:
+ description: 'Container name: required for volumes,
+ optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format of the
+ exposed resources, defaults to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ secretKeyRef:
+ description: Selects a key of a secret in the pod's
+ namespace
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ envFrom:
+ description: List of sources to populate environment variables
+ in the container. The keys defined within a source must be
+ a C_IDENTIFIER. All invalid keys will be reported as an event
+ when the container is starting. When a key exists in multiple
+ sources, the value associated with the last source will take
+ precedence. Values defined by an Env with a duplicate key
+ will take precedence. Cannot be updated.
+ items:
+ description: EnvFromSource represents the source of a set
+ of ConfigMaps
+ properties:
+ configMapRef:
+ description: The ConfigMap to select from
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap must be
+ defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ prefix:
+ description: An optional identifier to prepend to each
+ key in the ConfigMap. Must be a C_IDENTIFIER.
+ type: string
+ secretRef:
+ description: The Secret to select from
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ type: array
+ image:
+ description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images
+ This field is optional to allow higher level config management
+ to default or override container images in workload controllers
+ like Deployments and StatefulSets.'
+ type: string
+ imagePullPolicy:
+ description: 'Image pull policy. One of Always, Never, IfNotPresent.
+ Defaults to Always if :latest tag is specified, or IfNotPresent
+ otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images'
+ type: string
+ lifecycle:
+ description: Actions that the management system should take
+ in response to container lifecycle events. Cannot be updated.
+ properties:
+ postStart:
+ description: 'PostStart is called immediately after a container
+ is created. If the handler fails, the container is terminated
+ and restarted according to its restart policy. Other management
+ of the container blocks until the hook completes. More
+ info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for
+ the command is root ('/') in the container's
+ filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions
+ ('|', etc) won't work. To use a shell, you need
+ to explicitly call out to that shell. Exit status
+ of 0 is treated as live/healthy and non-zero is
+ unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to
+ the pod IP. You probably want to set "Host" in
+ httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the
+ host. Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ tcpSocket:
+ description: Deprecated. TCPSocket is NOT supported
+ as a LifecycleHandler and kept for the backward compatibility.
+ There are no validation of this field and lifecycle
+ hooks will fail in runtime when tcp handler is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ preStop:
+ description: 'PreStop is called immediately before a container
+ is terminated due to an API request or management event
+ such as liveness/startup probe failure, preemption, resource
+ contention, etc. The handler is not called if the container
+ crashes or exits. The Pod''s termination grace period
+ countdown begins before the PreStop hook is executed.
+ Regardless of the outcome of the handler, the container
+ will eventually terminate within the Pod''s termination
+ grace period (unless delayed by finalizers). Other management
+ of the container blocks until the hook completes or until
+ the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for
+ the command is root ('/') in the container's
+ filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions
+ ('|', etc) won't work. To use a shell, you need
+ to explicitly call out to that shell. Exit status
+ of 0 is treated as live/healthy and non-zero is
+ unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to
+ the pod IP. You probably want to set "Host" in
+ httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the
+ host. Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ tcpSocket:
+ description: Deprecated. TCPSocket is NOT supported
+ as a LifecycleHandler and kept for the backward compatibility.
+ There are no validation of this field and lifecycle
+ hooks will fail in runtime when tcp handler is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ type: object
+ livenessProbe:
+ description: 'Periodic probe of container liveness. Container
+ will be restarted if the probe fails. Cannot be updated. More
+ info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ name:
+ description: Name of the container specified as a DNS_LABEL.
+ Each container in a pod must have a unique name (DNS_LABEL).
+ Cannot be updated.
+ type: string
+ ports:
+ description: List of ports to expose from the container. Not
+ specifying a port here DOES NOT prevent that port from being
+ exposed. Any port which is listening on the default "0.0.0.0"
+ address inside a container will be accessible from the network.
+ Modifying this array with strategic merge patch may corrupt
+ the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255.
+ Cannot be updated.
+ items:
+ description: ContainerPort represents a network port in a
+ single container.
+ properties:
+ containerPort:
+ description: Number of port to expose on the pod's IP
+ address. This must be a valid port number, 0 < x < 65536.
+ format: int32
+ type: integer
+ hostIP:
+ description: What host IP to bind the external port to.
+ type: string
+ hostPort:
+ description: Number of port to expose on the host. If
+ specified, this must be a valid port number, 0 < x <
+ 65536. If HostNetwork is specified, this must match
+ ContainerPort. Most containers do not need this.
+ format: int32
+ type: integer
+ name:
+ description: If specified, this must be an IANA_SVC_NAME
+ and unique within the pod. Each named port in a pod
+ must have a unique name. Name for the port that can
+ be referred to by services.
+ type: string
+ protocol:
+ default: TCP
+ description: Protocol for port. Must be UDP, TCP, or SCTP.
+ Defaults to "TCP".
+ type: string
+ required:
+ - containerPort
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - containerPort
+ - protocol
+ x-kubernetes-list-type: map
+ readinessProbe:
+ description: 'Periodic probe of container service readiness.
+ Container will be removed from service endpoints if the probe
+ fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ resources:
+ description: 'Compute Resources required by this container.
+ Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount of compute
+ resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount of compute
+ resources required. If Requests is omitted for a container,
+ it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. More info:
+ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ securityContext:
+ description: 'SecurityContext defines the security options the
+ container should be run with. If set, the fields of SecurityContext
+ override the equivalent fields of PodSecurityContext. More
+ info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/'
+ properties:
+ allowPrivilegeEscalation:
+ description: 'AllowPrivilegeEscalation controls whether
+ a process can gain more privileges than its parent process.
+ This bool directly controls if the no_new_privs flag will
+ be set on the container process. AllowPrivilegeEscalation
+ is true always when the container is: 1) run as Privileged
+ 2) has CAP_SYS_ADMIN Note that this field cannot be set
+ when spec.os.name is windows.'
+ type: boolean
+ capabilities:
+ description: The capabilities to add/drop when running containers.
+ Defaults to the default set of capabilities granted by
+ the container runtime. Note that this field cannot be
+ set when spec.os.name is windows.
+ properties:
+ add:
+ description: Added capabilities
+ items:
+ description: Capability represent POSIX capabilities
+ type
+ type: string
+ type: array
+ drop:
+ description: Removed capabilities
+ items:
+ description: Capability represent POSIX capabilities
+ type
+ type: string
+ type: array
+ type: object
+ privileged:
+ description: Run container in privileged mode. Processes
+ in privileged containers are essentially equivalent to
+ root on the host. Defaults to false. Note that this field
+ cannot be set when spec.os.name is windows.
+ type: boolean
+ procMount:
+ description: procMount denotes the type of proc mount to
+ use for the containers. The default is DefaultProcMount
+ which uses the container runtime defaults for readonly
+ paths and masked paths. This requires the ProcMountType
+ feature flag to be enabled. Note that this field cannot
+ be set when spec.os.name is windows.
+ type: string
+ readOnlyRootFilesystem:
+ description: Whether this container has a read-only root
+ filesystem. Default is false. Note that this field cannot
+ be set when spec.os.name is windows.
+ type: boolean
+ runAsGroup:
+ description: The GID to run the entrypoint of the container
+ process. Uses runtime default if unset. May also be set
+ in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence. Note that this field cannot be set when
+ spec.os.name is windows.
+ format: int64
+ type: integer
+ runAsNonRoot:
+ description: Indicates that the container must run as a
+ non-root user. If true, the Kubelet will validate the
+ image at runtime to ensure that it does not run as UID
+ 0 (root) and fail to start the container if it does. If
+ unset or false, no such validation will be performed.
+ May also be set in PodSecurityContext. If set in both
+ SecurityContext and PodSecurityContext, the value specified
+ in SecurityContext takes precedence.
+ type: boolean
+ runAsUser:
+ description: The UID to run the entrypoint of the container
+ process. Defaults to user specified in image metadata
+ if unspecified. May also be set in PodSecurityContext. If
+ set in both SecurityContext and PodSecurityContext, the
+ value specified in SecurityContext takes precedence. Note
+ that this field cannot be set when spec.os.name is windows.
+ format: int64
+ type: integer
+ seLinuxOptions:
+ description: The SELinux context to be applied to the container.
+ If unspecified, the container runtime will allocate a
+ random SELinux context for each container. May also be
+ set in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence. Note that this field cannot be set when
+ spec.os.name is windows.
+ properties:
+ level:
+ description: Level is SELinux level label that applies
+ to the container.
+ type: string
+ role:
+ description: Role is a SELinux role label that applies
+ to the container.
+ type: string
+ type:
+ description: Type is a SELinux type label that applies
+ to the container.
+ type: string
+ user:
+ description: User is a SELinux user label that applies
+ to the container.
+ type: string
+ type: object
+ seccompProfile:
+ description: The seccomp options to use by this container.
+ If seccomp options are provided at both the pod & container
+ level, the container options override the pod options.
+ Note that this field cannot be set when spec.os.name is
+ windows.
+ properties:
+ localhostProfile:
+ description: localhostProfile indicates a profile defined
+ in a file on the node should be used. The profile
+ must be preconfigured on the node to work. Must be
+ a descending path, relative to the kubelet's configured
+ seccomp profile location. Must only be set if type
+ is "Localhost".
+ type: string
+ type:
+ description: "type indicates which kind of seccomp profile
+ will be applied. Valid options are: \n Localhost -
+ a profile defined in a file on the node should be
+ used. RuntimeDefault - the container runtime default
+ profile should be used. Unconfined - no profile should
+ be applied."
+ type: string
+ required:
+ - type
+ type: object
+ windowsOptions:
+ description: The Windows specific settings applied to all
+ containers. If unspecified, the options from the PodSecurityContext
+ will be used. If set in both SecurityContext and PodSecurityContext,
+ the value specified in SecurityContext takes precedence.
+ Note that this field cannot be set when spec.os.name is
+ linux.
+ properties:
+ gmsaCredentialSpec:
+ description: GMSACredentialSpec is where the GMSA admission
+ webhook (https://github.com/kubernetes-sigs/windows-gmsa)
+ inlines the contents of the GMSA credential spec named
+ by the GMSACredentialSpecName field.
+ type: string
+ gmsaCredentialSpecName:
+ description: GMSACredentialSpecName is the name of the
+ GMSA credential spec to use.
+ type: string
+ hostProcess:
+ description: HostProcess determines if a container should
+ be run as a 'Host Process' container. This field is
+ alpha-level and will only be honored by components
+ that enable the WindowsHostProcessContainers feature
+ flag. Setting this field without the feature flag
+ will result in errors when validating the Pod. All
+ of a Pod's containers must have the same effective
+ HostProcess value (it is not allowed to have a mix
+ of HostProcess containers and non-HostProcess containers). In
+ addition, if HostProcess is true then HostNetwork
+ must also be set to true.
+ type: boolean
+ runAsUserName:
+ description: The UserName in Windows to run the entrypoint
+ of the container process. Defaults to the user specified
+ in image metadata if unspecified. May also be set
+ in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence.
+ type: string
+ type: object
+ type: object
+ startupProbe:
+ description: 'StartupProbe indicates that the Pod has successfully
+ initialized. If specified, no other probes are executed until
+ this completes successfully. If this probe fails, the Pod
+ will be restarted, just as if the livenessProbe failed. This
+ can be used to provide different probe parameters at the beginning
+ of a Pod''s lifecycle, when it might take a long time to load
+ data or warm a cache, than during steady-state operation.
+ This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ stdin:
+ description: Whether this container should allocate a buffer
+ for stdin in the container runtime. If this is not set, reads
+ from stdin in the container will always result in EOF. Default
+ is false.
+ type: boolean
+ stdinOnce:
+ description: Whether the container runtime should close the
+ stdin channel after it has been opened by a single attach.
+ When stdin is true the stdin stream will remain open across
+ multiple attach sessions. If stdinOnce is set to true, stdin
+ is opened on container start, is empty until the first client
+ attaches to stdin, and then remains open and accepts data
+ until the client disconnects, at which time stdin is closed
+ and remains closed until the container is restarted. If this
+ flag is false, a container processes that reads from stdin
+ will never receive an EOF. Default is false
+ type: boolean
+ terminationMessagePath:
+ description: 'Optional: Path at which the file to which the
+ container''s termination message will be written is mounted
+ into the container''s filesystem. Message written is intended
+ to be brief final status, such as an assertion failure message.
+ Will be truncated by the node if greater than 4096 bytes.
+ The total message length across all containers will be limited
+ to 12kb. Defaults to /dev/termination-log. Cannot be updated.'
+ type: string
+ terminationMessagePolicy:
+ description: Indicate how the termination message should be
+ populated. File will use the contents of terminationMessagePath
+ to populate the container status message on both success and
+ failure. FallbackToLogsOnError will use the last chunk of
+ container log output if the termination message file is empty
+ and the container exited with an error. The log output is
+ limited to 2048 bytes or 80 lines, whichever is smaller. Defaults
+ to File. Cannot be updated.
+ type: string
+ tty:
+ description: Whether this container should allocate a TTY for
+ itself, also requires 'stdin' to be true. Default is false.
+ type: boolean
+ volumeDevices:
+ description: volumeDevices is the list of block devices to be
+ used by the container.
+ items:
+ description: volumeDevice describes a mapping of a raw block
+ device within a container.
+ properties:
+ devicePath:
+ description: devicePath is the path inside of the container
+ that the device will be mapped to.
+ type: string
+ name:
+ description: name must match the name of a persistentVolumeClaim
+ in the pod
+ type: string
+ required:
+ - devicePath
+ - name
+ type: object
+ type: array
+ volumeMounts:
+ description: Pod volumes to mount into the container's filesystem.
+ Cannot be updated.
+ items:
+ description: VolumeMount describes a mounting of a Volume
+ within a container.
+ properties:
+ mountPath:
+ description: Path within the container at which the volume
+ should be mounted. Must not contain ':'.
+ type: string
+ mountPropagation:
+ description: mountPropagation determines how mounts are
+ propagated from the host to container and the other
+ way around. When not set, MountPropagationNone is used.
+ This field is beta in 1.10.
+ type: string
+ name:
+ description: This must match the Name of a Volume.
+ type: string
+ readOnly:
+ description: Mounted read-only if true, read-write otherwise
+ (false or unspecified). Defaults to false.
+ type: boolean
+ subPath:
+ description: Path within the volume from which the container's
+ volume should be mounted. Defaults to "" (volume's root).
+ type: string
+ subPathExpr:
+ description: Expanded path within the volume from which
+ the container's volume should be mounted. Behaves similarly
+ to SubPath but environment variable references $(VAR_NAME)
+ are expanded using the container's environment. Defaults
+ to "" (volume's root). SubPathExpr and SubPath are mutually
+ exclusive.
+ type: string
+ required:
+ - mountPath
+ - name
+ type: object
+ type: array
+ workingDir:
+ description: Container's working directory. If not specified,
+ the container runtime's default will be used, which might
+ be configured in the container image. Cannot be updated.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ enforcedNamespaceLabel:
+ description: EnforcedNamespaceLabel enforces adding a namespace label
+ of origin for each alert and metric that is user created. The label
+ value will always be the namespace of the object that is being created.
+ type: string
+ evaluationInterval:
+ default: 15s
+ description: Interval between consecutive evaluations.
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ excludedFromEnforcement:
+ description: List of references to PrometheusRule objects to be excluded
+ from enforcing a namespace label of origin. Applies only if enforcedNamespaceLabel
+ set to true.
+ items:
+ description: ObjectReference references a PodMonitor, ServiceMonitor,
+ Probe or PrometheusRule object.
+ properties:
+ group:
+ default: monitoring.coreos.com
+ description: Group of the referent. When not specified, it defaults
+ to `monitoring.coreos.com`
+ enum:
+ - monitoring.coreos.com
+ type: string
+ name:
+ description: Name of the referent. When not set, all resources
+ are matched.
+ type: string
+ namespace:
+ description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
+ minLength: 1
+ type: string
+ resource:
+ description: Resource of the referent.
+ enum:
+ - prometheusrules
+ - servicemonitors
+ - podmonitors
+ - probes
+ type: string
+ required:
+ - namespace
+ - resource
+ type: object
+ type: array
+ externalPrefix:
+ description: The external URL the Thanos Ruler instances will be available
+ under. This is necessary to generate correct URLs. This is necessary
+ if Thanos Ruler is not served from root of a DNS name.
+ type: string
+ grpcServerTlsConfig:
+ description: 'GRPCServerTLSConfig configures the gRPC server from
+ which Thanos Querier reads recorded rule data. Note: Currently only
+ the CAFile, CertFile, and KeyFile fields are supported. Maps to
+ the ''--grpc-server-tls-*'' CLI args.'
+ properties:
+ ca:
+ description: Struct containing the CA cert to use for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ caFile:
+ description: Path to the CA cert in the Prometheus container to
+ use for the targets.
+ type: string
+ cert:
+ description: Struct containing the client cert file for the targets.
+ properties:
+ configMap:
+ description: ConfigMap containing data to use for the targets.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secret:
+ description: Secret containing data to use for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ certFile:
+ description: Path to the client cert file in the Prometheus container
+ for the targets.
+ type: string
+ insecureSkipVerify:
+ description: Disable target certificate validation.
+ type: boolean
+ keyFile:
+ description: Path to the client key file in the Prometheus container
+ for the targets.
+ type: string
+ keySecret:
+ description: Secret containing the client key file for the targets.
+ properties:
+ key:
+ description: The key of the secret to select from. Must be
+ a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be
+ defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ serverName:
+ description: Used to verify the hostname for the targets.
+ type: string
+ type: object
+ hostAliases:
+ description: Pods' hostAliases configuration
+ items:
+ description: HostAlias holds the mapping between IP and hostnames
+ that will be injected as an entry in the pod's hosts file.
+ properties:
+ hostnames:
+ description: Hostnames for the above IP address.
+ items:
+ type: string
+ type: array
+ ip:
+ description: IP address of the host file entry.
+ type: string
+ required:
+ - hostnames
+ - ip
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - ip
+ x-kubernetes-list-type: map
+ image:
+ description: Thanos container image URL.
+ type: string
+ imagePullSecrets:
+ description: An optional list of references to secrets in the same
+ namespace to use for pulling thanos images from registries see http://kubernetes.io/docs/user-guide/images#specifying-imagepullsecrets-on-a-pod
+ items:
+ description: LocalObjectReference contains enough information to
+ let you locate the referenced object inside the same namespace.
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ initContainers:
+ description: 'InitContainers allows adding initContainers to the pod
+ definition. Those can be used to e.g. fetch secrets for injection
+ into the ThanosRuler configuration from external sources. Any errors
+ during the execution of an initContainer will lead to a restart
+ of the Pod. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
+ Using initContainers for any use case other then secret fetching
+ is entirely outside the scope of what the maintainers will support
+ and by doing so, you accept that this behaviour may break at any
+ time without notice.'
+ items:
+ description: A single application container that you want to run
+ within a pod.
+ properties:
+ args:
+ description: 'Arguments to the entrypoint. The container image''s
+ CMD is used if this is not provided. Variable references $(VAR_NAME)
+ are expanded using the container''s environment. If a variable
+ cannot be resolved, the reference in the input string will
+ be unchanged. Double $$ are reduced to a single $, which allows
+ for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
+ produce the string literal "$(VAR_NAME)". Escaped references
+ will never be expanded, regardless of whether the variable
+ exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
+ items:
+ type: string
+ type: array
+ command:
+ description: 'Entrypoint array. Not executed within a shell.
+ The container image''s ENTRYPOINT is used if this is not provided.
+ Variable references $(VAR_NAME) are expanded using the container''s
+ environment. If a variable cannot be resolved, the reference
+ in the input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME) syntax:
+ i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
+ Escaped references will never be expanded, regardless of whether
+ the variable exists or not. Cannot be updated. More info:
+ https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell'
+ items:
+ type: string
+ type: array
+ env:
+ description: List of environment variables to set in the container.
+ Cannot be updated.
+ items:
+ description: EnvVar represents an environment variable present
+ in a Container.
+ properties:
+ name:
+ description: Name of the environment variable. Must be
+ a C_IDENTIFIER.
+ type: string
+ value:
+ description: 'Variable references $(VAR_NAME) are expanded
+ using the previously defined environment variables in
+ the container and any service environment variables.
+ If a variable cannot be resolved, the reference in the
+ input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME)
+ syntax: i.e. "$$(VAR_NAME)" will produce the string
+ literal "$(VAR_NAME)". Escaped references will never
+ be expanded, regardless of whether the variable exists
+ or not. Defaults to "".'
+ type: string
+ valueFrom:
+ description: Source for the environment variable's value.
+ Cannot be used if value is not empty.
+ properties:
+ configMapKeyRef:
+ description: Selects a key of a ConfigMap.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ fieldRef:
+ description: 'Selects a field of the pod: supports
+ metadata.name, metadata.namespace, `metadata.labels['''']`,
+ `metadata.annotations['''']`, spec.nodeName,
+ spec.serviceAccountName, status.hostIP, status.podIP,
+ status.podIPs.'
+ properties:
+ apiVersion:
+ description: Version of the schema the FieldPath
+ is written in terms of, defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select in the
+ specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ resourceFieldRef:
+ description: 'Selects a resource of the container:
+ only resources limits and requests (limits.cpu,
+ limits.memory, limits.ephemeral-storage, requests.cpu,
+ requests.memory and requests.ephemeral-storage)
+ are currently supported.'
+ properties:
+ containerName:
+ description: 'Container name: required for volumes,
+ optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format of the
+ exposed resources, defaults to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ secretKeyRef:
+ description: Selects a key of a secret in the pod's
+ namespace
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ envFrom:
+ description: List of sources to populate environment variables
+ in the container. The keys defined within a source must be
+ a C_IDENTIFIER. All invalid keys will be reported as an event
+ when the container is starting. When a key exists in multiple
+ sources, the value associated with the last source will take
+ precedence. Values defined by an Env with a duplicate key
+ will take precedence. Cannot be updated.
+ items:
+ description: EnvFromSource represents the source of a set
+ of ConfigMaps
+ properties:
+ configMapRef:
+ description: The ConfigMap to select from
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap must be
+ defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ prefix:
+ description: An optional identifier to prepend to each
+ key in the ConfigMap. Must be a C_IDENTIFIER.
+ type: string
+ secretRef:
+ description: The Secret to select from
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ type: array
+ image:
+ description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images
+ This field is optional to allow higher level config management
+ to default or override container images in workload controllers
+ like Deployments and StatefulSets.'
+ type: string
+ imagePullPolicy:
+ description: 'Image pull policy. One of Always, Never, IfNotPresent.
+ Defaults to Always if :latest tag is specified, or IfNotPresent
+ otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images'
+ type: string
+ lifecycle:
+ description: Actions that the management system should take
+ in response to container lifecycle events. Cannot be updated.
+ properties:
+ postStart:
+ description: 'PostStart is called immediately after a container
+ is created. If the handler fails, the container is terminated
+ and restarted according to its restart policy. Other management
+ of the container blocks until the hook completes. More
+ info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for
+ the command is root ('/') in the container's
+ filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions
+ ('|', etc) won't work. To use a shell, you need
+ to explicitly call out to that shell. Exit status
+ of 0 is treated as live/healthy and non-zero is
+ unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to
+ the pod IP. You probably want to set "Host" in
+ httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the
+ host. Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ tcpSocket:
+ description: Deprecated. TCPSocket is NOT supported
+ as a LifecycleHandler and kept for the backward compatibility.
+ There are no validation of this field and lifecycle
+ hooks will fail in runtime when tcp handler is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ preStop:
+ description: 'PreStop is called immediately before a container
+ is terminated due to an API request or management event
+ such as liveness/startup probe failure, preemption, resource
+ contention, etc. The handler is not called if the container
+ crashes or exits. The Pod''s termination grace period
+ countdown begins before the PreStop hook is executed.
+ Regardless of the outcome of the handler, the container
+ will eventually terminate within the Pod''s termination
+ grace period (unless delayed by finalizers). Other management
+ of the container blocks until the hook completes or until
+ the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for
+ the command is root ('/') in the container's
+ filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions
+ ('|', etc) won't work. To use a shell, you need
+ to explicitly call out to that shell. Exit status
+ of 0 is treated as live/healthy and non-zero is
+ unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to
+ the pod IP. You probably want to set "Host" in
+ httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the
+ host. Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ tcpSocket:
+ description: Deprecated. TCPSocket is NOT supported
+ as a LifecycleHandler and kept for the backward compatibility.
+ There are no validation of this field and lifecycle
+ hooks will fail in runtime when tcp handler is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access
+ on the container. Number must be in the range
+ 1 to 65535. Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ type: object
+ livenessProbe:
+ description: 'Periodic probe of container liveness. Container
+ will be restarted if the probe fails. Cannot be updated. More
+ info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ name:
+ description: Name of the container specified as a DNS_LABEL.
+ Each container in a pod must have a unique name (DNS_LABEL).
+ Cannot be updated.
+ type: string
+ ports:
+ description: List of ports to expose from the container. Not
+ specifying a port here DOES NOT prevent that port from being
+ exposed. Any port which is listening on the default "0.0.0.0"
+ address inside a container will be accessible from the network.
+ Modifying this array with strategic merge patch may corrupt
+ the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255.
+ Cannot be updated.
+ items:
+ description: ContainerPort represents a network port in a
+ single container.
+ properties:
+ containerPort:
+ description: Number of port to expose on the pod's IP
+ address. This must be a valid port number, 0 < x < 65536.
+ format: int32
+ type: integer
+ hostIP:
+ description: What host IP to bind the external port to.
+ type: string
+ hostPort:
+ description: Number of port to expose on the host. If
+ specified, this must be a valid port number, 0 < x <
+ 65536. If HostNetwork is specified, this must match
+ ContainerPort. Most containers do not need this.
+ format: int32
+ type: integer
+ name:
+ description: If specified, this must be an IANA_SVC_NAME
+ and unique within the pod. Each named port in a pod
+ must have a unique name. Name for the port that can
+ be referred to by services.
+ type: string
+ protocol:
+ default: TCP
+ description: Protocol for port. Must be UDP, TCP, or SCTP.
+ Defaults to "TCP".
+ type: string
+ required:
+ - containerPort
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - containerPort
+ - protocol
+ x-kubernetes-list-type: map
+ readinessProbe:
+ description: 'Periodic probe of container service readiness.
+ Container will be removed from service endpoints if the probe
+ fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ resources:
+ description: 'Compute Resources required by this container.
+ Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount of compute
+ resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount of compute
+ resources required. If Requests is omitted for a container,
+ it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. More info:
+ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ securityContext:
+ description: 'SecurityContext defines the security options the
+ container should be run with. If set, the fields of SecurityContext
+ override the equivalent fields of PodSecurityContext. More
+ info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/'
+ properties:
+ allowPrivilegeEscalation:
+ description: 'AllowPrivilegeEscalation controls whether
+ a process can gain more privileges than its parent process.
+ This bool directly controls if the no_new_privs flag will
+ be set on the container process. AllowPrivilegeEscalation
+ is true always when the container is: 1) run as Privileged
+ 2) has CAP_SYS_ADMIN Note that this field cannot be set
+ when spec.os.name is windows.'
+ type: boolean
+ capabilities:
+ description: The capabilities to add/drop when running containers.
+ Defaults to the default set of capabilities granted by
+ the container runtime. Note that this field cannot be
+ set when spec.os.name is windows.
+ properties:
+ add:
+ description: Added capabilities
+ items:
+ description: Capability represent POSIX capabilities
+ type
+ type: string
+ type: array
+ drop:
+ description: Removed capabilities
+ items:
+ description: Capability represent POSIX capabilities
+ type
+ type: string
+ type: array
+ type: object
+ privileged:
+ description: Run container in privileged mode. Processes
+ in privileged containers are essentially equivalent to
+ root on the host. Defaults to false. Note that this field
+ cannot be set when spec.os.name is windows.
+ type: boolean
+ procMount:
+ description: procMount denotes the type of proc mount to
+ use for the containers. The default is DefaultProcMount
+ which uses the container runtime defaults for readonly
+ paths and masked paths. This requires the ProcMountType
+ feature flag to be enabled. Note that this field cannot
+ be set when spec.os.name is windows.
+ type: string
+ readOnlyRootFilesystem:
+ description: Whether this container has a read-only root
+ filesystem. Default is false. Note that this field cannot
+ be set when spec.os.name is windows.
+ type: boolean
+ runAsGroup:
+ description: The GID to run the entrypoint of the container
+ process. Uses runtime default if unset. May also be set
+ in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence. Note that this field cannot be set when
+ spec.os.name is windows.
+ format: int64
+ type: integer
+ runAsNonRoot:
+ description: Indicates that the container must run as a
+ non-root user. If true, the Kubelet will validate the
+ image at runtime to ensure that it does not run as UID
+ 0 (root) and fail to start the container if it does. If
+ unset or false, no such validation will be performed.
+ May also be set in PodSecurityContext. If set in both
+ SecurityContext and PodSecurityContext, the value specified
+ in SecurityContext takes precedence.
+ type: boolean
+ runAsUser:
+ description: The UID to run the entrypoint of the container
+ process. Defaults to user specified in image metadata
+ if unspecified. May also be set in PodSecurityContext. If
+ set in both SecurityContext and PodSecurityContext, the
+ value specified in SecurityContext takes precedence. Note
+ that this field cannot be set when spec.os.name is windows.
+ format: int64
+ type: integer
+ seLinuxOptions:
+ description: The SELinux context to be applied to the container.
+ If unspecified, the container runtime will allocate a
+ random SELinux context for each container. May also be
+ set in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence. Note that this field cannot be set when
+ spec.os.name is windows.
+ properties:
+ level:
+ description: Level is SELinux level label that applies
+ to the container.
+ type: string
+ role:
+ description: Role is a SELinux role label that applies
+ to the container.
+ type: string
+ type:
+ description: Type is a SELinux type label that applies
+ to the container.
+ type: string
+ user:
+ description: User is a SELinux user label that applies
+ to the container.
+ type: string
+ type: object
+ seccompProfile:
+ description: The seccomp options to use by this container.
+ If seccomp options are provided at both the pod & container
+ level, the container options override the pod options.
+ Note that this field cannot be set when spec.os.name is
+ windows.
+ properties:
+ localhostProfile:
+ description: localhostProfile indicates a profile defined
+ in a file on the node should be used. The profile
+ must be preconfigured on the node to work. Must be
+ a descending path, relative to the kubelet's configured
+ seccomp profile location. Must only be set if type
+ is "Localhost".
+ type: string
+ type:
+ description: "type indicates which kind of seccomp profile
+ will be applied. Valid options are: \n Localhost -
+ a profile defined in a file on the node should be
+ used. RuntimeDefault - the container runtime default
+ profile should be used. Unconfined - no profile should
+ be applied."
+ type: string
+ required:
+ - type
+ type: object
+ windowsOptions:
+ description: The Windows specific settings applied to all
+ containers. If unspecified, the options from the PodSecurityContext
+ will be used. If set in both SecurityContext and PodSecurityContext,
+ the value specified in SecurityContext takes precedence.
+ Note that this field cannot be set when spec.os.name is
+ linux.
+ properties:
+ gmsaCredentialSpec:
+ description: GMSACredentialSpec is where the GMSA admission
+ webhook (https://github.com/kubernetes-sigs/windows-gmsa)
+ inlines the contents of the GMSA credential spec named
+ by the GMSACredentialSpecName field.
+ type: string
+ gmsaCredentialSpecName:
+ description: GMSACredentialSpecName is the name of the
+ GMSA credential spec to use.
+ type: string
+ hostProcess:
+ description: HostProcess determines if a container should
+ be run as a 'Host Process' container. This field is
+ alpha-level and will only be honored by components
+ that enable the WindowsHostProcessContainers feature
+ flag. Setting this field without the feature flag
+ will result in errors when validating the Pod. All
+ of a Pod's containers must have the same effective
+ HostProcess value (it is not allowed to have a mix
+ of HostProcess containers and non-HostProcess containers). In
+ addition, if HostProcess is true then HostNetwork
+ must also be set to true.
+ type: boolean
+ runAsUserName:
+ description: The UserName in Windows to run the entrypoint
+ of the container process. Defaults to the user specified
+ in image metadata if unspecified. May also be set
+ in PodSecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence.
+ type: string
+ type: object
+ type: object
+ startupProbe:
+ description: 'StartupProbe indicates that the Pod has successfully
+ initialized. If specified, no other probes are executed until
+ this completes successfully. If this probe fails, the Pod
+ will be restarted, just as if the livenessProbe failed. This
+ can be used to provide different probe parameters at the beginning
+ of a Pod''s lifecycle, when it might take a long time to load
+ data or warm a cache, than during steady-state operation.
+ This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ properties:
+ exec:
+ description: Exec specifies the action to take.
+ properties:
+ command:
+ description: Command is the command line to execute
+ inside the container, the working directory for the
+ command is root ('/') in the container's filesystem.
+ The command is simply exec'd, it is not run inside
+ a shell, so traditional shell instructions ('|', etc)
+ won't work. To use a shell, you need to explicitly
+ call out to that shell. Exit status of 0 is treated
+ as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe
+ to be considered failed after having succeeded. Defaults
+ to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies an action involving a GRPC port.
+ This is a beta field and requires enabling GRPCContainerProbe
+ feature gate.
+ properties:
+ port:
+ description: Port number of the gRPC service. Number
+ must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ description: "Service is the name of the service to
+ place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+ \n If this is not specified, the default behavior
+ is defined by gRPC."
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies the http request to perform.
+ properties:
+ host:
+ description: Host name to connect to, defaults to the
+ pod IP. You probably want to set "Host" in httpHeaders
+ instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request. HTTP
+ allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: The header field name
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Name or number of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: 'Number of seconds after the container has
+ started before liveness probes are initiated. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe
+ to be considered successful after having failed. Defaults
+ to 1. Must be 1 for liveness and startup. Minimum value
+ is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies an action involving a TCP
+ port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to, defaults
+ to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Number or name of the port to access on
+ the container. Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs
+ to terminate gracefully upon probe failure. The grace
+ period is the duration in seconds after the processes
+ running in the pod are sent a termination signal and the
+ time when the processes are forcibly halted with a kill
+ signal. Set this value longer than the expected cleanup
+ time for your process. If this value is nil, the pod's
+ terminationGracePeriodSeconds will be used. Otherwise,
+ this value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates
+ stop immediately via the kill signal (no opportunity to
+ shut down). This is a beta field and requires enabling
+ ProbeTerminationGracePeriod feature gate. Minimum value
+ is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: 'Number of seconds after which the probe times
+ out. Defaults to 1 second. Minimum value is 1. More info:
+ https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
+ format: int32
+ type: integer
+ type: object
+ stdin:
+ description: Whether this container should allocate a buffer
+ for stdin in the container runtime. If this is not set, reads
+ from stdin in the container will always result in EOF. Default
+ is false.
+ type: boolean
+ stdinOnce:
+ description: Whether the container runtime should close the
+ stdin channel after it has been opened by a single attach.
+ When stdin is true the stdin stream will remain open across
+ multiple attach sessions. If stdinOnce is set to true, stdin
+ is opened on container start, is empty until the first client
+ attaches to stdin, and then remains open and accepts data
+ until the client disconnects, at which time stdin is closed
+ and remains closed until the container is restarted. If this
+ flag is false, a container processes that reads from stdin
+ will never receive an EOF. Default is false
+ type: boolean
+ terminationMessagePath:
+ description: 'Optional: Path at which the file to which the
+ container''s termination message will be written is mounted
+ into the container''s filesystem. Message written is intended
+ to be brief final status, such as an assertion failure message.
+ Will be truncated by the node if greater than 4096 bytes.
+ The total message length across all containers will be limited
+ to 12kb. Defaults to /dev/termination-log. Cannot be updated.'
+ type: string
+ terminationMessagePolicy:
+ description: Indicate how the termination message should be
+ populated. File will use the contents of terminationMessagePath
+ to populate the container status message on both success and
+ failure. FallbackToLogsOnError will use the last chunk of
+ container log output if the termination message file is empty
+ and the container exited with an error. The log output is
+ limited to 2048 bytes or 80 lines, whichever is smaller. Defaults
+ to File. Cannot be updated.
+ type: string
+ tty:
+ description: Whether this container should allocate a TTY for
+ itself, also requires 'stdin' to be true. Default is false.
+ type: boolean
+ volumeDevices:
+ description: volumeDevices is the list of block devices to be
+ used by the container.
+ items:
+ description: volumeDevice describes a mapping of a raw block
+ device within a container.
+ properties:
+ devicePath:
+ description: devicePath is the path inside of the container
+ that the device will be mapped to.
+ type: string
+ name:
+ description: name must match the name of a persistentVolumeClaim
+ in the pod
+ type: string
+ required:
+ - devicePath
+ - name
+ type: object
+ type: array
+ volumeMounts:
+ description: Pod volumes to mount into the container's filesystem.
+ Cannot be updated.
+ items:
+ description: VolumeMount describes a mounting of a Volume
+ within a container.
+ properties:
+ mountPath:
+ description: Path within the container at which the volume
+ should be mounted. Must not contain ':'.
+ type: string
+ mountPropagation:
+ description: mountPropagation determines how mounts are
+ propagated from the host to container and the other
+ way around. When not set, MountPropagationNone is used.
+ This field is beta in 1.10.
+ type: string
+ name:
+ description: This must match the Name of a Volume.
+ type: string
+ readOnly:
+ description: Mounted read-only if true, read-write otherwise
+ (false or unspecified). Defaults to false.
+ type: boolean
+ subPath:
+ description: Path within the volume from which the container's
+ volume should be mounted. Defaults to "" (volume's root).
+ type: string
+ subPathExpr:
+ description: Expanded path within the volume from which
+ the container's volume should be mounted. Behaves similarly
+ to SubPath but environment variable references $(VAR_NAME)
+ are expanded using the container's environment. Defaults
+ to "" (volume's root). SubPathExpr and SubPath are mutually
+ exclusive.
+ type: string
+ required:
+ - mountPath
+ - name
+ type: object
+ type: array
+ workingDir:
+ description: Container's working directory. If not specified,
+ the container runtime's default will be used, which might
+ be configured in the container image. Cannot be updated.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ labels:
+ additionalProperties:
+ type: string
+ description: Labels configure the external label pairs to ThanosRuler.
+ A default replica label `thanos_ruler_replica` will be always added as
+ a label with the value of the pod's name and it will be dropped
+ in the alerts.
+ type: object
+ listenLocal:
+ description: ListenLocal makes the Thanos ruler listen on loopback,
+ so that it does not bind against the Pod IP.
+ type: boolean
+ logFormat:
+ description: Log format for ThanosRuler to be configured with.
+ enum:
+ - ""
+ - logfmt
+ - json
+ type: string
+ logLevel:
+ description: Log level for ThanosRuler to be configured with.
+ enum:
+ - ""
+ - debug
+ - info
+ - warn
+ - error
+ type: string
+ minReadySeconds:
+ description: Minimum number of seconds for which a newly created pod
+ should be ready without any of its container crashing for it to
+ be considered available. Defaults to 0 (pod will be considered available
+ as soon as it is ready) This is an alpha field and requires enabling
+ StatefulSetMinReadySeconds feature gate.
+ format: int32
+ type: integer
+ nodeSelector:
+ additionalProperties:
+ type: string
+ description: Define which Nodes the Pods are scheduled on.
+ type: object
+ objectStorageConfig:
+ description: ObjectStorageConfig configures object storage in Thanos.
+ Alternative to ObjectStorageConfigFile, and lower order priority.
+ properties:
+ key:
+ description: The key of the secret to select from. Must be a
+ valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ objectStorageConfigFile:
+ description: ObjectStorageConfigFile specifies the path of the object
+ storage configuration file. When used alongside with ObjectStorageConfig,
+ ObjectStorageConfigFile takes precedence.
+ type: string
+ paused:
+ description: When a ThanosRuler deployment is paused, no actions except
+ for deletion will be performed on the underlying objects.
+ type: boolean
+ podMetadata:
+ description: PodMetadata contains Labels and Annotations gets propagated
+ to the thanos ruler pods.
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: 'Annotations is an unstructured key value map stored
+ with a resource that may be set by external tools to store and
+ retrieve arbitrary metadata. They are not queryable and should
+ be preserved when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations'
+ type: object
+ labels:
+ additionalProperties:
+ type: string
+ description: 'Map of string keys and values that can be used to
+ organize and categorize (scope and select) objects. May match
+ selectors of replication controllers and services. More info:
+ http://kubernetes.io/docs/user-guide/labels'
+ type: object
+ name:
+ description: 'Name must be unique within a namespace. Is required
+ when creating resources, although some resources may allow a
+ client to request the generation of an appropriate name automatically.
+ Name is primarily intended for creation idempotence and configuration
+ definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names'
+ type: string
+ type: object
+ portName:
+ description: Port name used for the pods and governing service. This
+ defaults to web
+ type: string
+ priorityClassName:
+ description: Priority class assigned to the Pods
+ type: string
+ prometheusRulesExcludedFromEnforce:
+ description: 'PrometheusRulesExcludedFromEnforce - list of Prometheus
+ rules to be excluded from enforcing of adding namespace labels.
+ Works only if enforcedNamespaceLabel set to true. Make sure both
+ ruleNamespace and ruleName are set for each pair Deprecated: use
+ excludedFromEnforcement instead.'
+ items:
+ description: PrometheusRuleExcludeConfig enables users to configure
+ excluded PrometheusRule names and their namespaces to be ignored
+ while enforcing namespace label for alerts and metrics.
+ properties:
+ ruleName:
+ description: RuleNamespace - name of excluded rule
+ type: string
+ ruleNamespace:
+ description: RuleNamespace - namespace of excluded rule
+ type: string
+ required:
+ - ruleName
+ - ruleNamespace
+ type: object
+ type: array
+ queryConfig:
+ description: Define configuration for connecting to thanos query instances.
+ If this is defined, the QueryEndpoints field will be ignored. Maps
+ to the `query.config` CLI argument. Only available with thanos v0.11.0
+ and higher.
+ properties:
+ key:
+ description: The key of the secret to select from. Must be a
+ valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ queryEndpoints:
+ description: QueryEndpoints defines Thanos querier endpoints from
+ which to query metrics. Maps to the --query flag of thanos ruler.
+ items:
+ type: string
+ type: array
+ replicas:
+ description: Number of thanos ruler instances to deploy.
+ format: int32
+ type: integer
+ resources:
+ description: Resources defines the resource requirements for single
+ Pods. If not provided, no requests/limits will be set
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount of compute resources
+ allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount of compute
+ resources required. If Requests is omitted for a container,
+ it defaults to Limits if that is explicitly specified, otherwise
+ to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ retention:
+ default: 24h
+ description: Time duration ThanosRuler shall retain data for. Default
+ is '24h', and must match the regular expression `[0-9]+(ms|s|m|h|d|w|y)`
+ (milliseconds seconds minutes hours days weeks years).
+ pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
+ type: string
+ routePrefix:
+ description: The route prefix ThanosRuler registers HTTP handlers
+ for. This allows thanos UI to be served on a sub-path.
+ type: string
+ ruleNamespaceSelector:
+ description: Namespaces to be selected for Rules discovery. If unspecified,
+ only the same namespace as the ThanosRuler object is in is used.
+ 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
+ x-kubernetes-map-type: atomic
+ ruleSelector:
+ description: A label selector to select which PrometheusRules to mount
+ for alerting and recording.
+ 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
+ x-kubernetes-map-type: atomic
+ securityContext:
+ description: SecurityContext holds pod-level security attributes and
+ common container settings. This defaults to the default PodSecurityContext.
+ properties:
+ fsGroup:
+ description: "A special supplemental group that applies to all
+ containers in a pod. Some volume types allow the Kubelet to
+ change the ownership of that volume to be owned by the pod:
+ \n 1. The owning GID will be the FSGroup 2. The setgid bit is
+ set (new files created in the volume will be owned by FSGroup)
+ 3. The permission bits are OR'd with rw-rw---- \n If unset,
+ the Kubelet will not modify the ownership and permissions of
+ any volume. Note that this field cannot be set when spec.os.name
+ is windows."
+ format: int64
+ type: integer
+ fsGroupChangePolicy:
+ description: 'fsGroupChangePolicy defines behavior of changing
+ ownership and permission of the volume before being exposed
+ inside Pod. This field will only apply to volume types which
+ support fsGroup based ownership(and permissions). It will have
+ no effect on ephemeral volume types such as: secret, configmaps
+ and emptydir. Valid values are "OnRootMismatch" and "Always".
+ If not specified, "Always" is used. Note that this field cannot
+ be set when spec.os.name is windows.'
+ type: string
+ runAsGroup:
+ description: The GID to run the entrypoint of the container process.
+ Uses runtime default if unset. May also be set in SecurityContext. If
+ set in both SecurityContext and PodSecurityContext, the value
+ specified in SecurityContext takes precedence for that container.
+ Note that this field cannot be set when spec.os.name is windows.
+ format: int64
+ type: integer
+ runAsNonRoot:
+ description: Indicates that the container must run as a non-root
+ user. If true, the Kubelet will validate the image at runtime
+ to ensure that it does not run as UID 0 (root) and fail to start
+ the container if it does. If unset or false, no such validation
+ will be performed. May also be set in SecurityContext. If set
+ in both SecurityContext and PodSecurityContext, the value specified
+ in SecurityContext takes precedence.
+ type: boolean
+ runAsUser:
+ description: The UID to run the entrypoint of the container process.
+ Defaults to user specified in image metadata if unspecified.
+ May also be set in SecurityContext. If set in both SecurityContext
+ and PodSecurityContext, the value specified in SecurityContext
+ takes precedence for that container. Note that this field cannot
+ be set when spec.os.name is windows.
+ format: int64
+ type: integer
+ seLinuxOptions:
+ description: The SELinux context to be applied to all containers.
+ If unspecified, the container runtime will allocate a random
+ SELinux context for each container. May also be set in SecurityContext. If
+ set in both SecurityContext and PodSecurityContext, the value
+ specified in SecurityContext takes precedence for that container.
+ Note that this field cannot be set when spec.os.name is windows.
+ properties:
+ level:
+ description: Level is SELinux level label that applies to
+ the container.
+ type: string
+ role:
+ description: Role is a SELinux role label that applies to
+ the container.
+ type: string
+ type:
+ description: Type is a SELinux type label that applies to
+ the container.
+ type: string
+ user:
+ description: User is a SELinux user label that applies to
+ the container.
+ type: string
+ type: object
+ seccompProfile:
+ description: The seccomp options to use by the containers in this
+ pod. Note that this field cannot be set when spec.os.name is
+ windows.
+ properties:
+ localhostProfile:
+ description: localhostProfile indicates a profile defined
+ in a file on the node should be used. The profile must be
+ preconfigured on the node to work. Must be a descending
+ path, relative to the kubelet's configured seccomp profile
+ location. Must only be set if type is "Localhost".
+ type: string
+ type:
+ description: "type indicates which kind of seccomp profile
+ will be applied. Valid options are: \n Localhost - a profile
+ defined in a file on the node should be used. RuntimeDefault
+ - the container runtime default profile should be used.
+ Unconfined - no profile should be applied."
+ type: string
+ required:
+ - type
+ type: object
+ supplementalGroups:
+ description: A list of groups applied to the first process run
+ in each container, in addition to the container's primary GID. If
+ unspecified, no groups will be added to any container. Note
+ that this field cannot be set when spec.os.name is windows.
+ items:
+ format: int64
+ type: integer
+ type: array
+ sysctls:
+ description: Sysctls hold a list of namespaced sysctls used for
+ the pod. Pods with unsupported sysctls (by the container runtime)
+ might fail to launch. Note that this field cannot be set when
+ spec.os.name is windows.
+ items:
+ description: Sysctl defines a kernel parameter to be set
+ properties:
+ name:
+ description: Name of a property to set
+ type: string
+ value:
+ description: Value of a property to set
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ windowsOptions:
+ description: The Windows specific settings applied to all containers.
+ If unspecified, the options within a container's SecurityContext
+ will be used. If set in both SecurityContext and PodSecurityContext,
+ the value specified in SecurityContext takes precedence. Note
+ that this field cannot be set when spec.os.name is linux.
+ properties:
+ gmsaCredentialSpec:
+ description: GMSACredentialSpec is where the GMSA admission
+ webhook (https://github.com/kubernetes-sigs/windows-gmsa)
+ inlines the contents of the GMSA credential spec named by
+ the GMSACredentialSpecName field.
+ type: string
+ gmsaCredentialSpecName:
+ description: GMSACredentialSpecName is the name of the GMSA
+ credential spec to use.
+ type: string
+ hostProcess:
+ description: HostProcess determines if a container should
+ be run as a 'Host Process' container. This field is alpha-level
+ and will only be honored by components that enable the WindowsHostProcessContainers
+ feature flag. Setting this field without the feature flag
+ will result in errors when validating the Pod. All of a
+ Pod's containers must have the same effective HostProcess
+ value (it is not allowed to have a mix of HostProcess containers
+ and non-HostProcess containers). In addition, if HostProcess
+ is true then HostNetwork must also be set to true.
+ type: boolean
+ runAsUserName:
+ description: The UserName in Windows to run the entrypoint
+ of the container process. Defaults to the user specified
+ in image metadata if unspecified. May also be set in PodSecurityContext.
+ If set in both SecurityContext and PodSecurityContext, the
+ value specified in SecurityContext takes precedence.
+ type: string
+ type: object
+ type: object
+ serviceAccountName:
+ description: ServiceAccountName is the name of the ServiceAccount
+ to use to run the Thanos Ruler Pods.
+ type: string
+ storage:
+ description: Storage spec to specify how storage shall be used.
+ properties:
+ disableMountSubPath:
+ description: 'Deprecated: subPath usage will be disabled by default
+ in a future release, this option will become unnecessary. DisableMountSubPath
+ allows to remove any subPath usage in volume mounts.'
+ type: boolean
+ emptyDir:
+ description: 'EmptyDirVolumeSource to be used by the Prometheus
+ StatefulSets. If specified, used in place of any volumeClaimTemplate.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir'
+ properties:
+ medium:
+ description: 'medium represents what type of storage medium
+ should back this directory. The default is "" which means
+ to use the node''s default medium. Must be an empty string
+ (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir'
+ type: string
+ sizeLimit:
+ anyOf:
+ - type: integer
+ - type: string
+ description: 'sizeLimit is the total amount of local storage
+ required for this EmptyDir volume. The size limit is also
+ applicable for memory medium. The maximum usage on memory
+ medium EmptyDir would be the minimum value between the SizeLimit
+ specified here and the sum of memory limits of all containers
+ in a pod. The default is nil which means that the limit
+ is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir'
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type: object
+ ephemeral:
+ description: 'EphemeralVolumeSource to be used by the Prometheus
+ StatefulSets. This is a beta field in k8s 1.21, for lower versions,
+ starting with k8s 1.19, it requires enabling the GenericEphemeralVolume
+ feature gate. More info: https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/#generic-ephemeral-volumes'
+ properties:
+ volumeClaimTemplate:
+ description: "Will be used to create a stand-alone PVC to
+ provision the volume. The pod in which this EphemeralVolumeSource
+ is embedded will be the owner of the PVC, i.e. the PVC will
+ be deleted together with the pod. The name of the PVC will
+ be `-` where `` is the
+ name from the `PodSpec.Volumes` array entry. Pod validation
+ will reject the pod if the concatenated name is not valid
+ for a PVC (for example, too long). \n An existing PVC with
+ that name that is not owned by the pod will *not* be used
+ for the pod to avoid using an unrelated volume by mistake.
+ Starting the pod is then blocked until the unrelated PVC
+ is removed. If such a pre-created PVC is meant to be used
+ by the pod, the PVC has to updated with an owner reference
+ to the pod once the pod exists. Normally this should not
+ be necessary, but it may be useful when manually reconstructing
+ a broken cluster. \n This field is read-only and no changes
+ will be made by Kubernetes to the PVC after it has been
+ created. \n Required, must not be nil."
+ properties:
+ metadata:
+ description: May contain labels and annotations that will
+ be copied into the PVC when creating it. No other fields
+ are allowed and will be rejected during validation.
+ type: object
+ spec:
+ description: The specification for the PersistentVolumeClaim.
+ The entire content is copied unchanged into the PVC
+ that gets created from this template. The same fields
+ as in a PersistentVolumeClaim are also valid here.
+ properties:
+ accessModes:
+ description: 'accessModes contains the desired access
+ modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+ items:
+ type: string
+ type: array
+ dataSource:
+ description: 'dataSource field can be used to specify
+ either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
+ * An existing PVC (PersistentVolumeClaim) If the
+ provisioner or an external controller can support
+ the specified data source, it will create a new
+ volume based on the contents of the specified data
+ source. If the AnyVolumeDataSource feature gate
+ is enabled, this field will always have the same
+ contents as the DataSourceRef field.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is
+ required.
+ type: string
+ kind:
+ description: Kind is the type of resource being
+ referenced
+ type: string
+ name:
+ description: Name is the name of resource being
+ referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ dataSourceRef:
+ description: 'dataSourceRef specifies the object from
+ which to populate the volume with data, if a non-empty
+ volume is desired. This may be any local object
+ from a non-empty API group (non core object) or
+ a PersistentVolumeClaim object. When this field
+ is specified, volume binding will only succeed if
+ the type of the specified object matches some installed
+ volume populator or dynamic provisioner. This field
+ will replace the functionality of the DataSource
+ field and as such if both fields are non-empty,
+ they must have the same value. For backwards compatibility,
+ both fields (DataSource and DataSourceRef) will
+ be set to the same value automatically if one of
+ them is empty and the other is non-empty. There
+ are two important differences between DataSource
+ and DataSourceRef: * While DataSource only allows
+ two specific types of objects, DataSourceRef allows
+ any non-core object, as well as PersistentVolumeClaim
+ objects. * While DataSource ignores disallowed values
+ (dropping them), DataSourceRef preserves all values,
+ and generates an error if a disallowed value is
+ specified. (Beta) Using this field requires the
+ AnyVolumeDataSource feature gate to be enabled.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is
+ required.
+ type: string
+ kind:
+ description: Kind is the type of resource being
+ referenced
+ type: string
+ name:
+ description: Name is the name of resource being
+ referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ resources:
+ description: 'resources represents the minimum resources
+ the volume should have. If RecoverVolumeExpansionFailure
+ feature is enabled users are allowed to specify
+ resource requirements that are lower than previous
+ value but must still be higher than capacity recorded
+ in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount
+ of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount
+ of compute resources required. If Requests is
+ omitted for a container, it defaults to Limits
+ if that is explicitly specified, otherwise to
+ an implementation-defined value. More info:
+ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ selector:
+ description: selector is a label query over volumes
+ to consider for binding.
+ 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
+ x-kubernetes-map-type: atomic
+ storageClassName:
+ description: 'storageClassName is the name of the
+ StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
+ type: string
+ volumeMode:
+ description: volumeMode defines what type of volume
+ is required by the claim. Value of Filesystem is
+ implied when not included in claim spec.
+ type: string
+ volumeName:
+ description: volumeName is the binding reference to
+ the PersistentVolume backing this claim.
+ type: string
+ type: object
+ required:
+ - spec
+ type: object
+ type: object
+ volumeClaimTemplate:
+ description: A PVC spec to be used by the Prometheus StatefulSets.
+ 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:
+ description: EmbeddedMetadata contains metadata relevant to
+ an EmbeddedResource.
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ description: 'Annotations is an unstructured key value
+ map stored with a resource that may be set by external
+ tools to store and retrieve arbitrary metadata. They
+ are not queryable and should be preserved when modifying
+ objects. More info: http://kubernetes.io/docs/user-guide/annotations'
+ type: object
+ labels:
+ additionalProperties:
+ type: string
+ description: 'Map of string keys and values that can be
+ used to organize and categorize (scope and select) objects.
+ May match selectors of replication controllers and services.
+ More info: http://kubernetes.io/docs/user-guide/labels'
+ type: object
+ name:
+ description: 'Name must be unique within a namespace.
+ Is required when creating resources, although some resources
+ may allow a client to request the generation of an appropriate
+ name automatically. Name is primarily intended for creation
+ idempotence and configuration definition. Cannot be
+ updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names'
+ type: string
+ type: object
+ spec:
+ description: 'Spec defines the desired characteristics of
+ a volume requested by a pod author. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
+ properties:
+ accessModes:
+ description: 'accessModes contains the desired access
+ modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+ items:
+ type: string
+ type: array
+ dataSource:
+ description: 'dataSource field can be used to specify
+ either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
+ * An existing PVC (PersistentVolumeClaim) If the provisioner
+ or an external controller can support the specified
+ data source, it will create a new volume based on the
+ contents of the specified data source. If the AnyVolumeDataSource
+ feature gate is enabled, this field will always have
+ the same contents as the DataSourceRef field.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is required.
+ type: string
+ kind:
+ description: Kind is the type of resource being referenced
+ type: string
+ name:
+ description: Name is the name of resource being referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ dataSourceRef:
+ description: 'dataSourceRef specifies the object from
+ which to populate the volume with data, if a non-empty
+ volume is desired. This may be any local object from
+ a non-empty API group (non core object) or a PersistentVolumeClaim
+ object. When this field is specified, volume binding
+ will only succeed if the type of the specified object
+ matches some installed volume populator or dynamic provisioner.
+ This field will replace the functionality of the DataSource
+ field and as such if both fields are non-empty, they
+ must have the same value. For backwards compatibility,
+ both fields (DataSource and DataSourceRef) will be set
+ to the same value automatically if one of them is empty
+ and the other is non-empty. There are two important
+ differences between DataSource and DataSourceRef: *
+ While DataSource only allows two specific types of objects,
+ DataSourceRef allows any non-core object, as well as
+ PersistentVolumeClaim objects. * While DataSource ignores
+ disallowed values (dropping them), DataSourceRef preserves
+ all values, and generates an error if a disallowed value
+ is specified. (Beta) Using this field requires the AnyVolumeDataSource
+ feature gate to be enabled.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is required.
+ type: string
+ kind:
+ description: Kind is the type of resource being referenced
+ type: string
+ name:
+ description: Name is the name of resource being referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ resources:
+ description: 'resources represents the minimum resources
+ the volume should have. If RecoverVolumeExpansionFailure
+ feature is enabled users are allowed to specify resource
+ requirements that are lower than previous value but
+ must still be higher than capacity recorded in the status
+ field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount
+ of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount
+ of compute resources required. If Requests is omitted
+ for a container, it defaults to Limits if that is
+ explicitly specified, otherwise to an implementation-defined
+ value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ selector:
+ description: selector is a label query over volumes to
+ consider for binding.
+ 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
+ x-kubernetes-map-type: atomic
+ storageClassName:
+ description: 'storageClassName is the name of the StorageClass
+ required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
+ type: string
+ volumeMode:
+ description: volumeMode defines what type of volume is
+ required by the claim. Value of Filesystem is implied
+ when not included in claim spec.
+ type: string
+ volumeName:
+ description: volumeName is the binding reference to the
+ PersistentVolume backing this claim.
+ type: string
+ type: object
+ status:
+ description: 'Status represents the current information/status
+ of a persistent volume claim. Read-only. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
+ properties:
+ accessModes:
+ description: 'accessModes contains the actual access modes
+ the volume backing the PVC has. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+ items:
+ type: string
+ type: array
+ allocatedResources:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: allocatedResources is the storage resource
+ within AllocatedResources tracks the capacity allocated
+ to a PVC. It may be larger than the actual capacity
+ when a volume expansion operation is requested. For
+ storage quota, the larger value from allocatedResources
+ and PVC.spec.resources is used. If allocatedResources
+ is not set, PVC.spec.resources alone is used for quota
+ calculation. If a volume expansion capacity request
+ is lowered, allocatedResources is only lowered if there
+ are no expansion operations in progress and if the actual
+ volume capacity is equal or lower than the requested
+ capacity. This is an alpha field and requires enabling
+ RecoverVolumeExpansionFailure feature.
+ type: object
+ capacity:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: capacity represents the actual resources
+ of the underlying volume.
+ type: object
+ conditions:
+ description: conditions is the current Condition of persistent
+ volume claim. If underlying persistent volume is being
+ resized then the Condition will be set to 'ResizeStarted'.
+ items:
+ description: PersistentVolumeClaimCondition contails
+ details about state of pvc
+ properties:
+ lastProbeTime:
+ description: lastProbeTime is the time we probed
+ the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: lastTransitionTime is the time the
+ condition transitioned from one status to another.
+ format: date-time
+ type: string
+ message:
+ description: message is the human-readable message
+ indicating details about last transition.
+ type: string
+ reason:
+ description: reason is a unique, this should be
+ a short, machine understandable string that gives
+ the reason for condition's last transition. If
+ it reports "ResizeStarted" that means the underlying
+ persistent volume is being resized.
+ type: string
+ status:
+ type: string
+ type:
+ description: PersistentVolumeClaimConditionType
+ is a valid value of PersistentVolumeClaimCondition.Type
+ type: string
+ required:
+ - status
+ - type
+ type: object
+ type: array
+ phase:
+ description: phase represents the current phase of PersistentVolumeClaim.
+ type: string
+ resizeStatus:
+ description: resizeStatus stores status of resize operation.
+ ResizeStatus is not set by default but when expansion
+ is complete resizeStatus is set to empty string by resize
+ controller or kubelet. This is an alpha field and requires
+ enabling RecoverVolumeExpansionFailure feature.
+ type: string
+ type: object
+ type: object
+ type: object
+ tolerations:
+ description: If specified, the pod's tolerations.
+ items:
+ description: The pod this Toleration is attached to tolerates any
+ taint that matches the triple using the matching
+ operator .
+ properties:
+ effect:
+ description: Effect indicates the taint effect to match. Empty
+ means match all taint effects. When specified, allowed values
+ are NoSchedule, PreferNoSchedule and NoExecute.
+ type: string
+ key:
+ description: Key is the taint key that the toleration applies
+ to. Empty means match all taint keys. If the key is empty,
+ operator must be Exists; this combination means to match all
+ values and all keys.
+ type: string
+ operator:
+ description: Operator represents a key's relationship to the
+ value. Valid operators are Exists and Equal. Defaults to Equal.
+ Exists is equivalent to wildcard for value, so that a pod
+ can tolerate all taints of a particular category.
+ type: string
+ tolerationSeconds:
+ description: TolerationSeconds represents the period of time
+ the toleration (which must be of effect NoExecute, otherwise
+ this field is ignored) tolerates the taint. By default, it
+ is not set, which means tolerate the taint forever (do not
+ evict). Zero and negative values will be treated as 0 (evict
+ immediately) by the system.
+ format: int64
+ type: integer
+ value:
+ description: Value is the taint value the toleration matches
+ to. If the operator is Exists, the value should be empty,
+ otherwise just a regular string.
+ type: string
+ type: object
+ type: array
+ topologySpreadConstraints:
+ description: If specified, the pod's topology spread constraints.
+ items:
+ description: TopologySpreadConstraint specifies how to spread matching
+ pods among the given topology.
+ properties:
+ labelSelector:
+ description: LabelSelector is used to find matching pods. Pods
+ that match this label selector are counted to determine the
+ number of pods in their corresponding topology domain.
+ 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
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: MatchLabelKeys is a set of pod label keys to select
+ the pods over which spreading will be calculated. The keys
+ are used to lookup values from the incoming pod labels, those
+ key-value labels are ANDed with labelSelector to select the
+ group of existing pods over which spreading will be calculated
+ for the incoming pod. Keys that don't exist in the incoming
+ pod labels will be ignored. A null or empty list means only
+ match against labelSelector.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ maxSkew:
+ description: 'MaxSkew describes the degree to which pods may
+ be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`,
+ it is the maximum permitted difference between the number
+ of matching pods in the target topology and the global minimum.
+ The global minimum is the minimum number of matching pods
+ in an eligible domain or zero if the number of eligible domains
+ is less than MinDomains. For example, in a 3-zone cluster,
+ MaxSkew is set to 1, and pods with the same labelSelector
+ spread as 2/2/1: In this case, the global minimum is 1. |
+ zone1 | zone2 | zone3 | | P P | P P | P | - if MaxSkew
+ is 1, incoming pod can only be scheduled to zone3 to become
+ 2/2/2; scheduling it onto zone1(zone2) would make the ActualSkew(3-1)
+ on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming
+ pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`,
+ it is used to give higher precedence to topologies that satisfy
+ it. It''s a required field. Default value is 1 and 0 is not
+ allowed.'
+ format: int32
+ type: integer
+ minDomains:
+ description: "MinDomains indicates a minimum number of eligible
+ domains. When the number of eligible domains with matching
+ topology keys is less than minDomains, Pod Topology Spread
+ treats \"global minimum\" as 0, and then the calculation of
+ Skew is performed. And when the number of eligible domains
+ with matching topology keys equals or greater than minDomains,
+ this value has no effect on scheduling. As a result, when
+ the number of eligible domains is less than minDomains, scheduler
+ won't schedule more than maxSkew Pods to those domains. If
+ value is nil, the constraint behaves as if MinDomains is equal
+ to 1. Valid values are integers greater than 0. When value
+ is not nil, WhenUnsatisfiable must be DoNotSchedule. \n For
+ example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains
+ is set to 5 and pods with the same labelSelector spread as
+ 2/2/2: | zone1 | zone2 | zone3 | | P P | P P | P P |
+ The number of domains is less than 5(MinDomains), so \"global
+ minimum\" is treated as 0. In this situation, new pod with
+ the same labelSelector cannot be scheduled, because computed
+ skew will be 3(3 - 0) if new Pod is scheduled to any of the
+ three zones, it will violate MaxSkew. \n This is a beta field
+ and requires the MinDomainsInPodTopologySpread feature gate
+ to be enabled (enabled by default)."
+ format: int32
+ type: integer
+ nodeAffinityPolicy:
+ description: "NodeAffinityPolicy indicates how we will treat
+ Pod's nodeAffinity/nodeSelector when calculating pod topology
+ spread skew. Options are: - Honor: only nodes matching nodeAffinity/nodeSelector
+ are included in the calculations. - Ignore: nodeAffinity/nodeSelector
+ are ignored. All nodes are included in the calculations. \n
+ If this value is nil, the behavior is equivalent to the Honor
+ policy. This is a alpha-level feature enabled by the NodeInclusionPolicyInPodTopologySpread
+ feature flag."
+ type: string
+ nodeTaintsPolicy:
+ description: "NodeTaintsPolicy indicates how we will treat node
+ taints when calculating pod topology spread skew. Options
+ are: - Honor: nodes without taints, along with tainted nodes
+ for which the incoming pod has a toleration, are included.
+ - Ignore: node taints are ignored. All nodes are included.
+ \n If this value is nil, the behavior is equivalent to the
+ Ignore policy. This is a alpha-level feature enabled by the
+ NodeInclusionPolicyInPodTopologySpread feature flag."
+ type: string
+ topologyKey:
+ description: TopologyKey is the key of node labels. Nodes that
+ have a label with this key and identical values are considered
+ to be in the same topology. We consider each
+ as a "bucket", and try to put balanced number of pods into
+ each bucket. We define a domain as a particular instance of
+ a topology. Also, we define an eligible domain as a domain
+ whose nodes meet the requirements of nodeAffinityPolicy and
+ nodeTaintsPolicy. e.g. If TopologyKey is "kubernetes.io/hostname",
+ each Node is a domain of that topology. And, if TopologyKey
+ is "topology.kubernetes.io/zone", each zone is a domain of
+ that topology. It's a required field.
+ type: string
+ whenUnsatisfiable:
+ description: 'WhenUnsatisfiable indicates how to deal with a
+ pod if it doesn''t satisfy the spread constraint. - DoNotSchedule
+ (default) tells the scheduler not to schedule it. - ScheduleAnyway
+ tells the scheduler to schedule the pod in any location, but
+ giving higher precedence to topologies that would help reduce
+ the skew. A constraint is considered "Unsatisfiable" for an
+ incoming pod if and only if every possible node assignment
+ for that pod would violate "MaxSkew" on some topology. For
+ example, in a 3-zone cluster, MaxSkew is set to 1, and pods
+ with the same labelSelector spread as 3/1/1: | zone1 | zone2
+ | zone3 | | P P P | P | P | If WhenUnsatisfiable is
+ set to DoNotSchedule, incoming pod can only be scheduled to
+ zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on
+ zone2(zone3) satisfies MaxSkew(1). In other words, the cluster
+ can still be imbalanced, but scheduler won''t make it *more*
+ imbalanced. It''s a required field.'
+ type: string
+ required:
+ - maxSkew
+ - topologyKey
+ - whenUnsatisfiable
+ type: object
+ type: array
+ tracingConfig:
+ description: TracingConfig configures tracing in Thanos. This is an
+ experimental feature, it may change in any upcoming release in a
+ breaking way.
+ properties:
+ key:
+ description: The key of the secret to select from. Must be a
+ valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ tracingConfigFile:
+ description: TracingConfig specifies the path of the tracing configuration
+ file. When used alongside with TracingConfig, TracingConfigFile
+ takes precedence.
+ type: string
+ volumes:
+ description: Volumes allows configuration of additional volumes on
+ the output StatefulSet definition. Volumes specified will be appended
+ to other volumes that are generated as a result of StorageSpec objects.
+ items:
+ description: Volume represents a named volume in a pod that may
+ be accessed by any container in the pod.
+ properties:
+ awsElasticBlockStore:
+ description: 'awsElasticBlockStore represents an AWS Disk resource
+ that is attached to a kubelet''s host machine and then exposed
+ to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore'
+ properties:
+ fsType:
+ description: 'fsType is the filesystem type of the volume
+ that you want to mount. Tip: Ensure that the filesystem
+ type is supported by the host operating system. Examples:
+ "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore
+ TODO: how do we prevent errors in the filesystem from
+ compromising the machine'
+ type: string
+ partition:
+ description: 'partition is the partition in the volume that
+ you want to mount. If omitted, the default is to mount
+ by volume name. Examples: For volume /dev/sda1, you specify
+ the partition as "1". Similarly, the volume partition
+ for /dev/sda is "0" (or you can leave the property empty).'
+ format: int32
+ type: integer
+ readOnly:
+ description: 'readOnly value true will force the readOnly
+ setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore'
+ type: boolean
+ volumeID:
+ description: 'volumeID is unique ID of the persistent disk
+ resource in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore'
+ type: string
+ required:
+ - volumeID
+ type: object
+ azureDisk:
+ description: azureDisk represents an Azure Data Disk mount on
+ the host and bind mount to the pod.
+ properties:
+ cachingMode:
+ description: 'cachingMode is the Host Caching mode: None,
+ Read Only, Read Write.'
+ type: string
+ diskName:
+ description: diskName is the Name of the data disk in the
+ blob storage
+ type: string
+ diskURI:
+ description: diskURI is the URI of data disk in the blob
+ storage
+ type: string
+ fsType:
+ description: fsType is Filesystem type to mount. Must be
+ a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ kind:
+ description: 'kind expected values are Shared: multiple
+ blob disks per storage account Dedicated: single blob
+ disk per storage account Managed: azure managed data
+ disk (only in managed availability set). defaults to shared'
+ type: string
+ readOnly:
+ description: readOnly Defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ required:
+ - diskName
+ - diskURI
+ type: object
+ azureFile:
+ description: azureFile represents an Azure File Service mount
+ on the host and bind mount to the pod.
+ properties:
+ readOnly:
+ description: readOnly defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretName:
+ description: secretName is the name of secret that contains
+ Azure Storage Account Name and Key
+ type: string
+ shareName:
+ description: shareName is the azure share Name
+ type: string
+ required:
+ - secretName
+ - shareName
+ type: object
+ cephfs:
+ description: cephFS represents a Ceph FS mount on the host that
+ shares a pod's lifetime
+ properties:
+ monitors:
+ description: 'monitors is Required: Monitors is a collection
+ of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ items:
+ type: string
+ type: array
+ path:
+ description: 'path is Optional: Used as the mounted root,
+ rather than the full Ceph tree, default is /'
+ type: string
+ readOnly:
+ description: 'readOnly is Optional: Defaults to false (read/write).
+ ReadOnly here will force the ReadOnly setting in VolumeMounts.
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ type: boolean
+ secretFile:
+ description: 'secretFile is Optional: SecretFile is the
+ path to key ring for User, default is /etc/ceph/user.secret
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ type: string
+ secretRef:
+ description: 'secretRef is Optional: SecretRef is reference
+ to the authentication secret for User, default is empty.
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ user:
+ description: 'user is optional: User is the rados user name,
+ default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it'
+ type: string
+ required:
+ - monitors
+ type: object
+ cinder:
+ description: 'cinder represents a cinder volume attached and
+ mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md'
+ properties:
+ fsType:
+ description: 'fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Examples: "ext4", "xfs", "ntfs". Implicitly inferred to
+ be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md'
+ type: string
+ readOnly:
+ description: 'readOnly defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ More info: https://examples.k8s.io/mysql-cinder-pd/README.md'
+ type: boolean
+ secretRef:
+ description: 'secretRef is optional: points to a secret
+ object containing parameters used to connect to OpenStack.'
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ volumeID:
+ description: 'volumeID used to identify the volume in cinder.
+ More info: https://examples.k8s.io/mysql-cinder-pd/README.md'
+ type: string
+ required:
+ - volumeID
+ type: object
+ configMap:
+ description: configMap represents a configMap that should populate
+ this volume
+ properties:
+ defaultMode:
+ description: 'defaultMode is optional: mode bits used to
+ set permissions on created files by default. Must be an
+ octal value between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. Defaults to
+ 0644. Directories within the path are not affected by
+ this setting. This might be in conflict with other options
+ that affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ items:
+ description: items if unspecified, each key-value pair in
+ the Data field of the referenced ConfigMap will be projected
+ into the volume as a file whose name is the key and content
+ is the value. If specified, the listed keys will be projected
+ into the specified paths, and unlisted keys will not be
+ present. If a key is specified which is not present in
+ the ConfigMap, the volume setup will error unless it is
+ marked optional. Paths must be relative and may not contain
+ the '..' path or start with '..'.
+ items:
+ description: Maps a string key to a path within a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: 'mode is Optional: mode bits used to
+ set permissions on this file. Must be an octal value
+ between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. If not
+ specified, the volume defaultMode will be used.
+ This might be in conflict with other options that
+ affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: path is the relative path of the file
+ to map the key to. May not be an absolute path.
+ May not contain the path element '..'. May not start
+ with the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ optional:
+ description: optional specify whether the ConfigMap or its
+ keys must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ csi:
+ description: csi (Container Storage Interface) represents ephemeral
+ storage that is handled by certain external CSI drivers (Beta
+ feature).
+ properties:
+ driver:
+ description: driver is the name of the CSI driver that handles
+ this volume. Consult with your admin for the correct name
+ as registered in the cluster.
+ type: string
+ fsType:
+ description: fsType to mount. Ex. "ext4", "xfs", "ntfs".
+ If not provided, the empty value is passed to the associated
+ CSI driver which will determine the default filesystem
+ to apply.
+ type: string
+ nodePublishSecretRef:
+ description: nodePublishSecretRef is a reference to the
+ secret object containing sensitive information to pass
+ to the CSI driver to complete the CSI NodePublishVolume
+ and NodeUnpublishVolume calls. This field is optional,
+ and may be empty if no secret is required. If the secret
+ object contains more than one secret, all secret references
+ are passed.
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ readOnly:
+ description: readOnly specifies a read-only configuration
+ for the volume. Defaults to false (read/write).
+ type: boolean
+ volumeAttributes:
+ additionalProperties:
+ type: string
+ description: volumeAttributes stores driver-specific properties
+ that are passed to the CSI driver. Consult your driver's
+ documentation for supported values.
+ type: object
+ required:
+ - driver
+ type: object
+ downwardAPI:
+ description: downwardAPI represents downward API about the pod
+ that should populate this volume
+ properties:
+ defaultMode:
+ description: 'Optional: mode bits to use on created files
+ by default. Must be a Optional: mode bits used to set
+ permissions on created files by default. Must be an octal
+ value between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. Defaults to
+ 0644. Directories within the path are not affected by
+ this setting. This might be in conflict with other options
+ that affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ items:
+ description: Items is a list of downward API volume file
+ items:
+ description: DownwardAPIVolumeFile represents information
+ to create the file containing the pod field
+ properties:
+ fieldRef:
+ description: 'Required: Selects a field of the pod:
+ only annotations, labels, name and namespace are
+ supported.'
+ properties:
+ apiVersion:
+ description: Version of the schema the FieldPath
+ is written in terms of, defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select in the
+ specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ mode:
+ description: 'Optional: mode bits used to set permissions
+ on this file, must be an octal value between 0000
+ and 0777 or a decimal value between 0 and 511. YAML
+ accepts both octal and decimal values, JSON requires
+ decimal values for mode bits. If not specified,
+ the volume defaultMode will be used. This might
+ be in conflict with other options that affect the
+ file mode, like fsGroup, and the result can be other
+ mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: 'Required: Path is the relative path
+ name of the file to be created. Must not be absolute
+ or contain the ''..'' path. Must be utf-8 encoded.
+ The first item of the relative path must not start
+ with ''..'''
+ type: string
+ resourceFieldRef:
+ description: 'Selects a resource of the container:
+ only resources limits and requests (limits.cpu,
+ limits.memory, requests.cpu and requests.memory)
+ are currently supported.'
+ properties:
+ containerName:
+ description: 'Container name: required for volumes,
+ optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format of the
+ exposed resources, defaults to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ required:
+ - path
+ type: object
+ type: array
+ type: object
+ emptyDir:
+ description: 'emptyDir represents a temporary directory that
+ shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir'
+ properties:
+ medium:
+ description: 'medium represents what type of storage medium
+ should back this directory. The default is "" which means
+ to use the node''s default medium. Must be an empty string
+ (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir'
+ type: string
+ sizeLimit:
+ anyOf:
+ - type: integer
+ - type: string
+ description: 'sizeLimit is the total amount of local storage
+ required for this EmptyDir volume. The size limit is also
+ applicable for memory medium. The maximum usage on memory
+ medium EmptyDir would be the minimum value between the
+ SizeLimit specified here and the sum of memory limits
+ of all containers in a pod. The default is nil which means
+ that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir'
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type: object
+ ephemeral:
+ description: "ephemeral represents a volume that is handled
+ by a cluster storage driver. The volume's lifecycle is tied
+ to the pod that defines it - it will be created before the
+ pod starts, and deleted when the pod is removed. \n Use this
+ if: a) the volume is only needed while the pod runs, b) features
+ of normal volumes like restoring from snapshot or capacity
+ tracking are needed, c) the storage driver is specified through
+ a storage class, and d) the storage driver supports dynamic
+ volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource
+ for more information on the connection between this volume
+ type and PersistentVolumeClaim). \n Use PersistentVolumeClaim
+ or one of the vendor-specific APIs for volumes that persist
+ for longer than the lifecycle of an individual pod. \n Use
+ CSI for light-weight local ephemeral volumes if the CSI driver
+ is meant to be used that way - see the documentation of the
+ driver for more information. \n A pod can use both types of
+ ephemeral volumes and persistent volumes at the same time."
+ properties:
+ volumeClaimTemplate:
+ description: "Will be used to create a stand-alone PVC to
+ provision the volume. The pod in which this EphemeralVolumeSource
+ is embedded will be the owner of the PVC, i.e. the PVC
+ will be deleted together with the pod. The name of the
+ PVC will be `-` where `` is the name from the `PodSpec.Volumes` array entry.
+ Pod validation will reject the pod if the concatenated
+ name is not valid for a PVC (for example, too long). \n
+ An existing PVC with that name that is not owned by the
+ pod will *not* be used for the pod to avoid using an unrelated
+ volume by mistake. Starting the pod is then blocked until
+ the unrelated PVC is removed. If such a pre-created PVC
+ is meant to be used by the pod, the PVC has to updated
+ with an owner reference to the pod once the pod exists.
+ Normally this should not be necessary, but it may be useful
+ when manually reconstructing a broken cluster. \n This
+ field is read-only and no changes will be made by Kubernetes
+ to the PVC after it has been created. \n Required, must
+ not be nil."
+ properties:
+ metadata:
+ description: May contain labels and annotations that
+ will be copied into the PVC when creating it. No other
+ fields are allowed and will be rejected during validation.
+ type: object
+ spec:
+ description: The specification for the PersistentVolumeClaim.
+ The entire content is copied unchanged into the PVC
+ that gets created from this template. The same fields
+ as in a PersistentVolumeClaim are also valid here.
+ properties:
+ accessModes:
+ description: 'accessModes contains the desired access
+ modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
+ items:
+ type: string
+ type: array
+ dataSource:
+ description: 'dataSource field can be used to specify
+ either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
+ * An existing PVC (PersistentVolumeClaim) If the
+ provisioner or an external controller can support
+ the specified data source, it will create a new
+ volume based on the contents of the specified
+ data source. If the AnyVolumeDataSource feature
+ gate is enabled, this field will always have the
+ same contents as the DataSourceRef field.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API
+ group. For any other third-party types, APIGroup
+ is required.
+ type: string
+ kind:
+ description: Kind is the type of resource being
+ referenced
+ type: string
+ name:
+ description: Name is the name of resource being
+ referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ dataSourceRef:
+ description: 'dataSourceRef specifies the object
+ from which to populate the volume with data, if
+ a non-empty volume is desired. This may be any
+ local object from a non-empty API group (non core
+ object) or a PersistentVolumeClaim object. When
+ this field is specified, volume binding will only
+ succeed if the type of the specified object matches
+ some installed volume populator or dynamic provisioner.
+ This field will replace the functionality of the
+ DataSource field and as such if both fields are
+ non-empty, they must have the same value. For
+ backwards compatibility, both fields (DataSource
+ and DataSourceRef) will be set to the same value
+ automatically if one of them is empty and the
+ other is non-empty. There are two important differences
+ between DataSource and DataSourceRef: * While
+ DataSource only allows two specific types of objects,
+ DataSourceRef allows any non-core object, as well
+ as PersistentVolumeClaim objects. * While DataSource
+ ignores disallowed values (dropping them), DataSourceRef
+ preserves all values, and generates an error if
+ a disallowed value is specified. (Beta) Using
+ this field requires the AnyVolumeDataSource feature
+ gate to be enabled.'
+ properties:
+ apiGroup:
+ description: APIGroup is the group for the resource
+ being referenced. If APIGroup is not specified,
+ the specified Kind must be in the core API
+ group. For any other third-party types, APIGroup
+ is required.
+ type: string
+ kind:
+ description: Kind is the type of resource being
+ referenced
+ type: string
+ name:
+ description: Name is the name of resource being
+ referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ resources:
+ description: 'resources represents the minimum resources
+ the volume should have. If RecoverVolumeExpansionFailure
+ feature is enabled users are allowed to specify
+ resource requirements that are lower than previous
+ value but must still be higher than capacity recorded
+ in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount
+ of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum
+ amount of compute resources required. If Requests
+ is omitted for a container, it defaults to
+ Limits if that is explicitly specified, otherwise
+ to an implementation-defined value. More info:
+ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ selector:
+ description: selector is a label query over volumes
+ to consider for binding.
+ 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
+ x-kubernetes-map-type: atomic
+ storageClassName:
+ description: 'storageClassName is the name of the
+ StorageClass required by the claim. More info:
+ https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
+ type: string
+ volumeMode:
+ description: volumeMode defines what type of volume
+ is required by the claim. Value of Filesystem
+ is implied when not included in claim spec.
+ type: string
+ volumeName:
+ description: volumeName is the binding reference
+ to the PersistentVolume backing this claim.
+ type: string
+ type: object
+ required:
+ - spec
+ type: object
+ type: object
+ fc:
+ description: fc represents a Fibre Channel resource that is
+ attached to a kubelet's host machine and then exposed to the
+ pod.
+ properties:
+ fsType:
+ description: 'fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified. TODO: how do we prevent errors in the
+ filesystem from compromising the machine'
+ type: string
+ lun:
+ description: 'lun is Optional: FC target lun number'
+ format: int32
+ type: integer
+ readOnly:
+ description: 'readOnly is Optional: Defaults to false (read/write).
+ ReadOnly here will force the ReadOnly setting in VolumeMounts.'
+ type: boolean
+ targetWWNs:
+ description: 'targetWWNs is Optional: FC target worldwide
+ names (WWNs)'
+ items:
+ type: string
+ type: array
+ wwids:
+ description: 'wwids Optional: FC volume world wide identifiers
+ (wwids) Either wwids or combination of targetWWNs and
+ lun must be set, but not both simultaneously.'
+ items:
+ type: string
+ type: array
+ type: object
+ flexVolume:
+ description: flexVolume represents a generic volume resource
+ that is provisioned/attached using an exec based plugin.
+ properties:
+ driver:
+ description: driver is the name of the driver to use for
+ this volume.
+ type: string
+ fsType:
+ description: fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". The default filesystem depends
+ on FlexVolume script.
+ type: string
+ options:
+ additionalProperties:
+ type: string
+ description: 'options is Optional: this field holds extra
+ command options if any.'
+ type: object
+ readOnly:
+ description: 'readOnly is Optional: defaults to false (read/write).
+ ReadOnly here will force the ReadOnly setting in VolumeMounts.'
+ type: boolean
+ secretRef:
+ description: 'secretRef is Optional: secretRef is reference
+ to the secret object containing sensitive information
+ to pass to the plugin scripts. This may be empty if no
+ secret object is specified. If the secret object contains
+ more than one secret, all secrets are passed to the plugin
+ scripts.'
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ required:
+ - driver
+ type: object
+ flocker:
+ description: flocker represents a Flocker volume attached to
+ a kubelet's host machine. This depends on the Flocker control
+ service being running
+ properties:
+ datasetName:
+ description: datasetName is Name of the dataset stored as
+ metadata -> name on the dataset for Flocker should be
+ considered as deprecated
+ type: string
+ datasetUUID:
+ description: datasetUUID is the UUID of the dataset. This
+ is unique identifier of a Flocker dataset
+ type: string
+ type: object
+ gcePersistentDisk:
+ description: 'gcePersistentDisk represents a GCE Disk resource
+ that is attached to a kubelet''s host machine and then exposed
+ to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk'
+ properties:
+ fsType:
+ description: 'fsType is filesystem type of the volume that
+ you want to mount. Tip: Ensure that the filesystem type
+ is supported by the host operating system. Examples: "ext4",
+ "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk
+ TODO: how do we prevent errors in the filesystem from
+ compromising the machine'
+ type: string
+ partition:
+ description: 'partition is the partition in the volume that
+ you want to mount. If omitted, the default is to mount
+ by volume name. Examples: For volume /dev/sda1, you specify
+ the partition as "1". Similarly, the volume partition
+ for /dev/sda is "0" (or you can leave the property empty).
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk'
+ format: int32
+ type: integer
+ pdName:
+ description: 'pdName is unique name of the PD resource in
+ GCE. Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk'
+ type: string
+ readOnly:
+ description: 'readOnly here will force the ReadOnly setting
+ in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk'
+ type: boolean
+ required:
+ - pdName
+ type: object
+ gitRepo:
+ description: 'gitRepo represents a git repository at a particular
+ revision. DEPRECATED: GitRepo is deprecated. To provision
+ a container with a git repo, mount an EmptyDir into an InitContainer
+ that clones the repo using git, then mount the EmptyDir into
+ the Pod''s container.'
+ properties:
+ directory:
+ description: directory is the target directory name. Must
+ not contain or start with '..'. If '.' is supplied, the
+ volume directory will be the git repository. Otherwise,
+ if specified, the volume will contain the git repository
+ in the subdirectory with the given name.
+ type: string
+ repository:
+ description: repository is the URL
+ type: string
+ revision:
+ description: revision is the commit hash for the specified
+ revision.
+ type: string
+ required:
+ - repository
+ type: object
+ glusterfs:
+ description: 'glusterfs represents a Glusterfs mount on the
+ host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md'
+ properties:
+ endpoints:
+ description: 'endpoints is the endpoint name that details
+ Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod'
+ type: string
+ path:
+ description: 'path is the Glusterfs volume path. More info:
+ https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod'
+ type: string
+ readOnly:
+ description: 'readOnly here will force the Glusterfs volume
+ to be mounted with read-only permissions. Defaults to
+ false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod'
+ type: boolean
+ required:
+ - endpoints
+ - path
+ type: object
+ hostPath:
+ description: 'hostPath represents a pre-existing file or directory
+ on the host machine that is directly exposed to the container.
+ This is generally used for system agents or other privileged
+ things that are allowed to see the host machine. Most containers
+ will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath
+ --- TODO(jonesdl) We need to restrict who can use host directory
+ mounts and who can/can not mount host directories as read/write.'
+ properties:
+ path:
+ description: 'path of the directory on the host. If the
+ path is a symlink, it will follow the link to the real
+ path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath'
+ type: string
+ type:
+ description: 'type for HostPath Volume Defaults to "" More
+ info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath'
+ type: string
+ required:
+ - path
+ type: object
+ iscsi:
+ description: 'iscsi represents an ISCSI Disk resource that is
+ attached to a kubelet''s host machine and then exposed to
+ the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md'
+ properties:
+ chapAuthDiscovery:
+ description: chapAuthDiscovery defines whether support iSCSI
+ Discovery CHAP authentication
+ type: boolean
+ chapAuthSession:
+ description: chapAuthSession defines whether support iSCSI
+ Session CHAP authentication
+ type: boolean
+ fsType:
+ description: 'fsType is the filesystem type of the volume
+ that you want to mount. Tip: Ensure that the filesystem
+ type is supported by the host operating system. Examples:
+ "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi
+ TODO: how do we prevent errors in the filesystem from
+ compromising the machine'
+ type: string
+ initiatorName:
+ description: initiatorName is the custom iSCSI Initiator
+ Name. If initiatorName is specified with iscsiInterface
+ simultaneously, new iSCSI interface : will be created for the connection.
+ type: string
+ iqn:
+ description: iqn is the target iSCSI Qualified Name.
+ type: string
+ iscsiInterface:
+ description: iscsiInterface is the interface Name that uses
+ an iSCSI transport. Defaults to 'default' (tcp).
+ type: string
+ lun:
+ description: lun represents iSCSI Target Lun number.
+ format: int32
+ type: integer
+ portals:
+ description: portals is the iSCSI Target Portal List. The
+ portal is either an IP or ip_addr:port if the port is
+ other than default (typically TCP ports 860 and 3260).
+ items:
+ type: string
+ type: array
+ readOnly:
+ description: readOnly here will force the ReadOnly setting
+ in VolumeMounts. Defaults to false.
+ type: boolean
+ secretRef:
+ description: secretRef is the CHAP Secret for iSCSI target
+ and initiator authentication
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ targetPortal:
+ description: targetPortal is iSCSI Target Portal. The Portal
+ is either an IP or ip_addr:port if the port is other than
+ default (typically TCP ports 860 and 3260).
+ type: string
+ required:
+ - iqn
+ - lun
+ - targetPortal
+ type: object
+ name:
+ description: 'name of the volume. Must be a DNS_LABEL and unique
+ within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
+ type: string
+ nfs:
+ description: 'nfs represents an NFS mount on the host that shares
+ a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs'
+ properties:
+ path:
+ description: 'path that is exported by the NFS server. More
+ info: https://kubernetes.io/docs/concepts/storage/volumes#nfs'
+ type: string
+ readOnly:
+ description: 'readOnly here will force the NFS export to
+ be mounted with read-only permissions. Defaults to false.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs'
+ type: boolean
+ server:
+ description: 'server is the hostname or IP address of the
+ NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs'
+ type: string
+ required:
+ - path
+ - server
+ type: object
+ persistentVolumeClaim:
+ description: 'persistentVolumeClaimVolumeSource represents a
+ reference to a PersistentVolumeClaim in the same namespace.
+ More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
+ properties:
+ claimName:
+ description: 'claimName is the name of a PersistentVolumeClaim
+ in the same namespace as the pod using this volume. More
+ info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
+ type: string
+ readOnly:
+ description: readOnly Will force the ReadOnly setting in
+ VolumeMounts. Default false.
+ type: boolean
+ required:
+ - claimName
+ type: object
+ photonPersistentDisk:
+ description: photonPersistentDisk represents a PhotonController
+ persistent disk attached and mounted on kubelets host machine
+ properties:
+ fsType:
+ description: fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ pdID:
+ description: pdID is the ID that identifies Photon Controller
+ persistent disk
+ type: string
+ required:
+ - pdID
+ type: object
+ portworxVolume:
+ description: portworxVolume represents a portworx volume attached
+ and mounted on kubelets host machine
+ properties:
+ fsType:
+ description: fSType represents the filesystem type to mount
+ Must be a filesystem type supported by the host operating
+ system. Ex. "ext4", "xfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ readOnly:
+ description: readOnly defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ volumeID:
+ description: volumeID uniquely identifies a Portworx volume
+ type: string
+ required:
+ - volumeID
+ type: object
+ projected:
+ description: projected items for all in one resources secrets,
+ configmaps, and downward API
+ properties:
+ defaultMode:
+ description: defaultMode are the mode bits used to set permissions
+ on created files by default. Must be an octal value between
+ 0000 and 0777 or a decimal value between 0 and 511. YAML
+ accepts both octal and decimal values, JSON requires decimal
+ values for mode bits. Directories within the path are
+ not affected by this setting. This might be in conflict
+ with other options that affect the file mode, like fsGroup,
+ and the result can be other mode bits set.
+ format: int32
+ type: integer
+ sources:
+ description: sources is the list of volume projections
+ items:
+ description: Projection that may be projected along with
+ other supported volume types
+ properties:
+ configMap:
+ description: configMap information about the configMap
+ data to project
+ properties:
+ items:
+ description: items if unspecified, each key-value
+ pair in the Data field of the referenced ConfigMap
+ will be projected into the volume as a file
+ whose name is the key and content is the value.
+ If specified, the listed keys will be projected
+ into the specified paths, and unlisted keys
+ will not be present. If a key is specified which
+ is not present in the ConfigMap, the volume
+ setup will error unless it is marked optional.
+ Paths must be relative and may not contain the
+ '..' path or start with '..'.
+ items:
+ description: Maps a string key to a path within
+ a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: 'mode is Optional: mode bits
+ used to set permissions on this file.
+ Must be an octal value between 0000 and
+ 0777 or a decimal value between 0 and
+ 511. YAML accepts both octal and decimal
+ values, JSON requires decimal values for
+ mode bits. If not specified, the volume
+ defaultMode will be used. This might be
+ in conflict with other options that affect
+ the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: path is the relative path of
+ the file to map the key to. May not be
+ an absolute path. May not contain the
+ path element '..'. May not start with
+ the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: optional specify whether the ConfigMap
+ or its keys must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ downwardAPI:
+ description: downwardAPI information about the downwardAPI
+ data to project
+ properties:
+ items:
+ description: Items is a list of DownwardAPIVolume
+ file
+ items:
+ description: DownwardAPIVolumeFile represents
+ information to create the file containing
+ the pod field
+ properties:
+ fieldRef:
+ description: 'Required: Selects a field
+ of the pod: only annotations, labels,
+ name and namespace are supported.'
+ properties:
+ apiVersion:
+ description: Version of the schema the
+ FieldPath is written in terms of,
+ defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select
+ in the specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ mode:
+ description: 'Optional: mode bits used to
+ set permissions on this file, must be
+ an octal value between 0000 and 0777 or
+ a decimal value between 0 and 511. YAML
+ accepts both octal and decimal values,
+ JSON requires decimal values for mode
+ bits. If not specified, the volume defaultMode
+ will be used. This might be in conflict
+ with other options that affect the file
+ mode, like fsGroup, and the result can
+ be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: 'Required: Path is the relative
+ path name of the file to be created. Must
+ not be absolute or contain the ''..''
+ path. Must be utf-8 encoded. The first
+ item of the relative path must not start
+ with ''..'''
+ type: string
+ resourceFieldRef:
+ description: 'Selects a resource of the
+ container: only resources limits and requests
+ (limits.cpu, limits.memory, requests.cpu
+ and requests.memory) are currently supported.'
+ properties:
+ containerName:
+ description: 'Container name: required
+ for volumes, optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format
+ of the exposed resources, defaults
+ to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to
+ select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ required:
+ - path
+ type: object
+ type: array
+ type: object
+ secret:
+ description: secret information about the secret data
+ to project
+ properties:
+ items:
+ description: items if unspecified, each key-value
+ pair in the Data field of the referenced Secret
+ will be projected into the volume as a file
+ whose name is the key and content is the value.
+ If specified, the listed keys will be projected
+ into the specified paths, and unlisted keys
+ will not be present. If a key is specified which
+ is not present in the Secret, the volume setup
+ will error unless it is marked optional. Paths
+ must be relative and may not contain the '..'
+ path or start with '..'.
+ items:
+ description: Maps a string key to a path within
+ a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: 'mode is Optional: mode bits
+ used to set permissions on this file.
+ Must be an octal value between 0000 and
+ 0777 or a decimal value between 0 and
+ 511. YAML accepts both octal and decimal
+ values, JSON requires decimal values for
+ mode bits. If not specified, the volume
+ defaultMode will be used. This might be
+ in conflict with other options that affect
+ the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: path is the relative path of
+ the file to map the key to. May not be
+ an absolute path. May not contain the
+ path element '..'. May not start with
+ the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ name:
+ description: 'Name of the referent. More info:
+ https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind,
+ uid?'
+ type: string
+ optional:
+ description: optional field specify whether the
+ Secret or its key must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ serviceAccountToken:
+ description: serviceAccountToken is information about
+ the serviceAccountToken data to project
+ properties:
+ audience:
+ description: audience is the intended audience
+ of the token. A recipient of a token must identify
+ itself with an identifier specified in the audience
+ of the token, and otherwise should reject the
+ token. The audience defaults to the identifier
+ of the apiserver.
+ type: string
+ expirationSeconds:
+ description: expirationSeconds is the requested
+ duration of validity of the service account
+ token. As the token approaches expiration, the
+ kubelet volume plugin will proactively rotate
+ the service account token. The kubelet will
+ start trying to rotate the token if the token
+ is older than 80 percent of its time to live
+ or if the token is older than 24 hours.Defaults
+ to 1 hour and must be at least 10 minutes.
+ format: int64
+ type: integer
+ path:
+ description: path is the path relative to the
+ mount point of the file to project the token
+ into.
+ type: string
+ required:
+ - path
+ type: object
+ type: object
+ type: array
+ type: object
+ quobyte:
+ description: quobyte represents a Quobyte mount on the host
+ that shares a pod's lifetime
+ properties:
+ group:
+ description: group to map volume access to Default is no
+ group
+ type: string
+ readOnly:
+ description: readOnly here will force the Quobyte volume
+ to be mounted with read-only permissions. Defaults to
+ false.
+ type: boolean
+ registry:
+ description: registry represents a single or multiple Quobyte
+ Registry services specified as a string as host:port pair
+ (multiple entries are separated with commas) which acts
+ as the central registry for volumes
+ type: string
+ tenant:
+ description: tenant owning the given Quobyte volume in the
+ Backend Used with dynamically provisioned Quobyte volumes,
+ value is set by the plugin
+ type: string
+ user:
+ description: user to map volume access to Defaults to serivceaccount
+ user
+ type: string
+ volume:
+ description: volume is a string that references an already
+ created Quobyte volume by name.
+ type: string
+ required:
+ - registry
+ - volume
+ type: object
+ rbd:
+ description: 'rbd represents a Rados Block Device mount on the
+ host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md'
+ properties:
+ fsType:
+ description: 'fsType is the filesystem type of the volume
+ that you want to mount. Tip: Ensure that the filesystem
+ type is supported by the host operating system. Examples:
+ "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd
+ TODO: how do we prevent errors in the filesystem from
+ compromising the machine'
+ type: string
+ image:
+ description: 'image is the rados image name. More info:
+ https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: string
+ keyring:
+ description: 'keyring is the path to key ring for RBDUser.
+ Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: string
+ monitors:
+ description: 'monitors is a collection of Ceph monitors.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ items:
+ type: string
+ type: array
+ pool:
+ description: 'pool is the rados pool name. Default is rbd.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: string
+ readOnly:
+ description: 'readOnly here will force the ReadOnly setting
+ in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: boolean
+ secretRef:
+ description: 'secretRef is name of the authentication secret
+ for RBDUser. If provided overrides keyring. Default is
+ nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ user:
+ description: 'user is the rados user name. Default is admin.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it'
+ type: string
+ required:
+ - image
+ - monitors
+ type: object
+ scaleIO:
+ description: scaleIO represents a ScaleIO persistent volume
+ attached and mounted on Kubernetes nodes.
+ properties:
+ fsType:
+ description: fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Default is "xfs".
+ type: string
+ gateway:
+ description: gateway is the host address of the ScaleIO
+ API Gateway.
+ type: string
+ protectionDomain:
+ description: protectionDomain is the name of the ScaleIO
+ Protection Domain for the configured storage.
+ type: string
+ readOnly:
+ description: readOnly Defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretRef:
+ description: secretRef references to the secret for ScaleIO
+ user and other sensitive information. If this is not provided,
+ Login operation will fail.
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ sslEnabled:
+ description: sslEnabled Flag enable/disable SSL communication
+ with Gateway, default false
+ type: boolean
+ storageMode:
+ description: storageMode indicates whether the storage for
+ a volume should be ThickProvisioned or ThinProvisioned.
+ Default is ThinProvisioned.
+ type: string
+ storagePool:
+ description: storagePool is the ScaleIO Storage Pool associated
+ with the protection domain.
+ type: string
+ system:
+ description: system is the name of the storage system as
+ configured in ScaleIO.
+ type: string
+ volumeName:
+ description: volumeName is the name of a volume already
+ created in the ScaleIO system that is associated with
+ this volume source.
+ type: string
+ required:
+ - gateway
+ - secretRef
+ - system
+ type: object
+ secret:
+ description: 'secret represents a secret that should populate
+ this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
+ properties:
+ defaultMode:
+ description: 'defaultMode is Optional: mode bits used to
+ set permissions on created files by default. Must be an
+ octal value between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. Defaults to
+ 0644. Directories within the path are not affected by
+ this setting. This might be in conflict with other options
+ that affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ items:
+ description: items If unspecified, each key-value pair in
+ the Data field of the referenced Secret will be projected
+ into the volume as a file whose name is the key and content
+ is the value. If specified, the listed keys will be projected
+ into the specified paths, and unlisted keys will not be
+ present. If a key is specified which is not present in
+ the Secret, the volume setup will error unless it is marked
+ optional. Paths must be relative and may not contain the
+ '..' path or start with '..'.
+ items:
+ description: Maps a string key to a path within a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: 'mode is Optional: mode bits used to
+ set permissions on this file. Must be an octal value
+ between 0000 and 0777 or a decimal value between
+ 0 and 511. YAML accepts both octal and decimal values,
+ JSON requires decimal values for mode bits. If not
+ specified, the volume defaultMode will be used.
+ This might be in conflict with other options that
+ affect the file mode, like fsGroup, and the result
+ can be other mode bits set.'
+ format: int32
+ type: integer
+ path:
+ description: path is the relative path of the file
+ to map the key to. May not be an absolute path.
+ May not contain the path element '..'. May not start
+ with the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ optional:
+ description: optional field specify whether the Secret or
+ its keys must be defined
+ type: boolean
+ secretName:
+ description: 'secretName is the name of the secret in the
+ pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret'
+ type: string
+ type: object
+ storageos:
+ description: storageOS represents a StorageOS volume attached
+ and mounted on Kubernetes nodes.
+ properties:
+ fsType:
+ description: fsType is the filesystem type to mount. Must
+ be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ readOnly:
+ description: readOnly defaults to false (read/write). ReadOnly
+ here will force the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretRef:
+ description: secretRef specifies the secret to use for obtaining
+ the StorageOS API credentials. If not specified, default
+ values will be attempted.
+ properties:
+ name:
+ description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion, kind, uid?'
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ volumeName:
+ description: volumeName is the human-readable name of the
+ StorageOS volume. Volume names are only unique within
+ a namespace.
+ type: string
+ volumeNamespace:
+ description: volumeNamespace specifies the scope of the
+ volume within StorageOS. If no namespace is specified
+ then the Pod's namespace will be used. This allows the
+ Kubernetes name scoping to be mirrored within StorageOS
+ for tighter integration. Set VolumeName to any name to
+ override the default behaviour. Set to "default" if you
+ are not using namespaces within StorageOS. Namespaces
+ that do not pre-exist within StorageOS will be created.
+ type: string
+ type: object
+ vsphereVolume:
+ description: vsphereVolume represents a vSphere volume attached
+ and mounted on kubelets host machine
+ properties:
+ fsType:
+ description: fsType is filesystem type to mount. Must be
+ a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4"
+ if unspecified.
+ type: string
+ storagePolicyID:
+ description: storagePolicyID is the storage Policy Based
+ Management (SPBM) profile ID associated with the StoragePolicyName.
+ type: string
+ storagePolicyName:
+ description: storagePolicyName is the storage Policy Based
+ Management (SPBM) profile name.
+ type: string
+ volumePath:
+ description: volumePath is the path that identifies vSphere
+ volume vmdk
+ type: string
+ required:
+ - volumePath
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ type: object
+ status:
+ description: 'Most recent observed status of the ThanosRuler cluster.
+ Read-only. Not included when requesting from the apiserver, only from
+ the ThanosRuler Operator API itself. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status'
+ properties:
+ availableReplicas:
+ description: Total number of available pods (ready for at least minReadySeconds)
+ targeted by this ThanosRuler deployment.
+ format: int32
+ type: integer
+ paused:
+ description: Represents whether any actions on the underlying managed
+ objects are being performed. Only delete actions will be performed.
+ type: boolean
+ replicas:
+ description: Total number of non-terminated pods targeted by this
+ ThanosRuler deployment (their labels match the selector).
+ format: int32
+ type: integer
+ unavailableReplicas:
+ description: Total number of unavailable pods targeted by this ThanosRuler
+ deployment.
+ format: int32
+ type: integer
+ updatedReplicas:
+ description: Total number of non-terminated pods targeted by this
+ ThanosRuler deployment that have the desired version spec.
+ format: int32
+ type: integer
+ required:
+ - availableReplicas
+ - paused
+ - replicas
+ - unavailableReplicas
+ - updatedReplicas
+ type: object
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
+ subresources: {}
diff --git a/kube-prometheus-stack/default-README.md b/kube-prometheus-stack/default-README.md
new file mode 100644
index 00000000..76982e2e
--- /dev/null
+++ b/kube-prometheus-stack/default-README.md
@@ -0,0 +1,707 @@
+# kube-prometheus-stack
+
+Installs the [kube-prometheus stack](https://github.com/prometheus-operator/kube-prometheus), a collection of Kubernetes manifests, [Grafana](http://grafana.com/) dashboards, and [Prometheus rules](https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/) combined with documentation and scripts to provide easy to operate end-to-end Kubernetes cluster monitoring with [Prometheus](https://prometheus.io/) using the [Prometheus Operator](https://github.com/prometheus-operator/prometheus-operator).
+
+See the [kube-prometheus](https://github.com/prometheus-operator/kube-prometheus) README for details about components, dashboards, and alerts.
+
+_Note: This chart was formerly named `prometheus-operator` chart, now renamed to more clearly reflect that it installs the `kube-prometheus` project stack, within which Prometheus Operator is only one component._
+
+## Prerequisites
+
+- Kubernetes 1.16+
+- Helm 3+
+
+## Get Helm Repository Info
+
+```console
+helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
+helm repo update
+```
+
+_See [`helm repo`](https://helm.sh/docs/helm/helm_repo/) for command documentation._
+
+## Install Helm Chart
+
+```console
+helm install [RELEASE_NAME] prometheus-community/kube-prometheus-stack
+```
+
+_See [configuration](#configuration) below._
+
+_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._
+
+## Dependencies
+
+By default this chart installs additional, dependent charts:
+
+- [prometheus-community/kube-state-metrics](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-state-metrics)
+- [prometheus-community/prometheus-node-exporter](https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-node-exporter)
+- [grafana/grafana](https://github.com/grafana/helm-charts/tree/main/charts/grafana)
+
+To disable dependencies during installation, see [multiple releases](#multiple-releases) below.
+
+_See [helm dependency](https://helm.sh/docs/helm/helm_dependency/) for command documentation._
+
+## Uninstall Helm Chart
+
+```console
+helm uninstall [RELEASE_NAME]
+```
+
+This removes all the Kubernetes components associated with the chart and deletes the release.
+
+_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._
+
+CRDs created by this chart are not removed by default and should be manually cleaned up:
+
+```console
+kubectl delete crd alertmanagerconfigs.monitoring.coreos.com
+kubectl delete crd alertmanagers.monitoring.coreos.com
+kubectl delete crd podmonitors.monitoring.coreos.com
+kubectl delete crd probes.monitoring.coreos.com
+kubectl delete crd prometheuses.monitoring.coreos.com
+kubectl delete crd prometheusrules.monitoring.coreos.com
+kubectl delete crd servicemonitors.monitoring.coreos.com
+kubectl delete crd thanosrulers.monitoring.coreos.com
+```
+
+## Upgrading Chart
+
+```console
+helm upgrade [RELEASE_NAME] prometheus-community/kube-prometheus-stack
+```
+
+With Helm v3, CRDs created by this chart are not updated by default and should be manually updated.
+Consult also the [Helm Documentation on CRDs](https://helm.sh/docs/chart_best_practices/custom_resource_definitions).
+
+_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._
+
+### Upgrading an existing Release to a new major version
+
+A major chart version change (like v1.2.3 -> v2.0.0) indicates that there is an incompatible breaking change needing manual actions.
+
+### From 39.x to 40.x
+
+This version upgrades Prometheus-Operator to v0.59.1, Prometheus to v2.38.0, kube-state-metrics to v2.6.0 and Thanos to v0.28.0.
+This version also upgrades the Helm charts of kube-state-metrics to 4.18.0 and prometheus-node-exporter to 4.2.0.
+
+Run these commands to update the CRDs before applying the upgrade.
+
+```console
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+```
+
+Starting from prometheus-node-exporter version 4.0.0, the `node exporter` chart is using the [Kubernetes recommended labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/). Therefore you have to delete the daemonset before you upgrade.
+
+```console
+kubectl delete daemonset -l app=prometheus-node-exporter
+helm upgrade -i kube-prometheus-stack prometheus-community/kube-prometheus-stack
+```
+
+If you use your own custom [ServiceMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitor) or [PodMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#podmonitor), please ensure to upgrade their `selector` fields accordingly to the new labels.
+
+### From 38.x to 39.x
+
+This upgraded prometheus-operator to v0.58.0 and prometheus to v2.37.0
+
+Run these commands to update the CRDs before applying the upgrade.
+
+```console
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+```
+
+### From 37.x to 38.x
+
+Reverted one of the default metrics relabelings for cAdvisor added in 36.x, due to it breaking container_network_* and various other statistics. If you do not want this change, you will need to override the `kubelet.cAdvisorMetricRelabelings`.
+
+### From 36.x to 37.x
+
+This includes some default metric relabelings for cAdvisor and apiserver metrics to reduce cardinality. If you do not want these defaults, you will need to override the `kubeApiServer.metricRelabelings` and or `kubelet.cAdvisorMetricRelabelings`.
+
+### From 35.x to 36.x
+
+This upgraded prometheus-operator to v0.57.0 and prometheus to v2.36.1
+
+Run these commands to update the CRDs before applying the upgrade.
+
+```console
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+```
+
+### From 34.x to 35.x
+
+This upgraded prometheus-operator to v0.56.0 and prometheus to v2.35.0
+
+Run these commands to update the CRDs before applying the upgrade.
+
+```console
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+```
+
+### From 33.x to 34.x
+
+This upgrades to prometheus-operator to v0.55.0 and prometheus to v2.33.5.
+
+Run these commands to update the CRDs before applying the upgrade.
+
+```console
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+```
+
+### From 32.x to 33.x
+
+This upgrades the prometheus-node-exporter Chart to v3.0.0. Please review the changes to this subchart if you make customizations to hostMountPropagation.
+
+### From 31.x to 32.x
+
+This upgrades to prometheus-operator to v0.54.0 and prometheus to v2.33.1. It also changes the default for `grafana.serviceMonitor.enabled` to `true.
+
+Run these commands to update the CRDs before applying the upgrade.
+
+```console
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+```
+
+### From 30.x to 31.x
+
+This version removes the built-in grafana ServiceMonitor and instead relies on the ServiceMonitor of the sub-chart.
+`grafana.serviceMonitor.enabled` must be set instead of `grafana.serviceMonitor.selfMonitor` and the old ServiceMonitor may
+need to be manually cleaned up after deploying the new release.
+
+### From 29.x to 30.x
+
+This version updates kube-state-metrics to 4.3.0 and uses the new option `kube-state-metrics.releaseLabel=true` which adds the "release" label to kube-state-metrics labels, making scraping of the metrics by kube-prometheus-stack work out of the box again, independent of the used kube-prometheus-stack release name. If you already set the "release" label via `kube-state-metrics.customLabels` you might have to remove that and use it via the new option.
+
+### From 28.x to 29.x
+
+This version makes scraping port for kube-controller-manager and kube-scheduler dynamic to reflect changes to default serving ports
+for those components in Kubernetes versions v1.22 and v1.23 respectively.
+
+If you deploy on clusters using version v1.22+, kube-controller-manager will be scraped over HTTPS on port 10257.
+
+If you deploy on clusters running version v1.23+, kube-scheduler will be scraped over HTTPS on port 10259.
+
+### From 27.x to 28.x
+
+This version disables PodSecurityPolicies by default because they are deprecated in Kubernetes 1.21 and will be removed in Kubernetes 1.25.
+
+If you are using PodSecurityPolicies you can enable the previous behaviour by setting `kube-state-metrics.podSecurityPolicy.enabled`, `prometheus-node-exporter.rbac.pspEnabled`, `grafana.rbac.pspEnabled` and `global.rbac.pspEnabled` to `true`.
+
+### From 26.x to 27.x
+
+This version splits prometheus-node-exporter chart recording and altering rules in separate config values.
+Instead of `defaultRules.rules.node` the 2 new variables `defaultRules.rules.nodeExporterAlerting` and `defaultRules.rules.nodeExporterRecording` are used.
+
+Also the following defaultRules.rules has been removed as they had no effect: `kubeApiserverError`, `kubePrometheusNodeAlerting`, `kubernetesAbsent`, `time`.
+
+The ability to set a rubookUrl via `defaultRules.rules.rubookUrl` was reintroduced.
+
+### From 25.x to 26.x
+
+This version enables the prometheus-node-exporter subchart servicemonitor by default again, by setting `prometheus-node-exporter.prometheus.monitor.enabled` to `true`.
+
+### From 24.x to 25.x
+
+This version upgrade to prometheus-operator v0.53.1. It removes support for setting a runbookUrl, since the upstream format for runbooks changed.
+
+```console
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+```
+
+### From 23.x to 24.x
+
+The custom `ServiceMonitor` for the _kube-state-metrics_ & _prometheus-node-exporter_ charts have been removed in favour of the built-in sub-chart `ServiceMonitor`; for both sub-charts this means that `ServiceMonitor` customisations happen via the values passed to the chart. If you haven't directly customised this behaviour then there are no changes required to upgrade, but if you have please read the following.
+
+For _kube-state-metrics_ the `ServiceMonitor` customisation is now set via `kube-state-metrics.prometheus.monitor` and the `kubeStateMetrics.serviceMonitor.selfMonitor.enabled` value has moved to `kube-state-metrics.selfMonitor.enabled`.
+
+For _prometheus-node-exporter_ the `ServiceMonitor` customisation is now set via `prometheus-node-exporter.prometheus.monitor` and the `nodeExporter.jobLabel` values has moved to `prometheus-node-exporter.prometheus.monitor.jobLabel`.
+
+### From 22.x to 23.x
+
+Port names have been renamed for Istio's
+[explicit protocol selection](https://istio.io/latest/docs/ops/configuration/traffic-management/protocol-selection/#explicit-protocol-selection).
+
+| | old value | new value |
+|-|-----------|-----------|
+| `alertmanager.alertmanagerSpec.portName` | `web` | `http-web` |
+| `grafana.service.portName` | `service` | `http-web` |
+| `prometheus-node-exporter.service.portName` | `metrics` (hardcoded) | `http-metrics` |
+| `prometheus.prometheusSpec.portName` | `web` | `http-web` |
+
+### From 21.x to 22.x
+
+Due to the upgrade of the `kube-state-metrics` chart, removal of its deployment/stateful needs to done manually prior to upgrading:
+
+```console
+kubectl delete deployments.apps -l app.kubernetes.io/instance=prometheus-operator,app.kubernetes.io/name=kube-state-metrics --cascade=orphan
+```
+
+or if you use autosharding:
+
+```console
+kubectl delete statefulsets.apps -l app.kubernetes.io/instance=prometheus-operator,app.kubernetes.io/name=kube-state-metrics --cascade=orphan
+```
+
+### From 20.x to 21.x
+
+The config reloader values have been refactored. All the values have been moved to the key `prometheusConfigReloader` and the limits and requests can now be set separately.
+
+### From 19.x to 20.x
+
+Version 20 upgrades prometheus-operator from 0.50.x to 0.52.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating:
+
+```console
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+```
+
+### From 18.x to 19.x
+
+`kubeStateMetrics.serviceMonitor.namespaceOverride` was removed.
+Please use `kube-state-metrics.namespaceOverride` instead.
+
+### From 17.x to 18.x
+
+Version 18 upgrades prometheus-operator from 0.49.x to 0.50.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating:
+
+```console
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+```
+
+### From 16.x to 17.x
+
+Version 17 upgrades prometheus-operator from 0.48.x to 0.49.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating:
+
+```console
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+```
+
+### From 15.x to 16.x
+
+Version 16 upgrades kube-state-metrics to v2.0.0. This includes changed command-line arguments and removed metrics, see this [blog post](https://kubernetes.io/blog/2021/04/13/kube-state-metrics-v-2-0/). This version also removes Grafana dashboards that supported Kubernetes 1.14 or earlier.
+
+### From 14.x to 15.x
+
+Version 15 upgrades prometheus-operator from 0.46.x to 0.47.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating:
+
+```console
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+```
+
+### From 13.x to 14.x
+
+Version 14 upgrades prometheus-operator from 0.45.x to 0.46.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating:
+
+```console
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml
+```
+
+### From 12.x to 13.x
+
+Version 13 upgrades prometheus-operator from 0.44.x to 0.45.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRD manually before updating:
+
+```console
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.45.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.45.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.45.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml
+```
+
+### From 11.x to 12.x
+
+Version 12 upgrades prometheus-operator from 0.43.x to 0.44.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRD manually before updating:
+
+```console
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/release-0.44/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml
+```
+
+The chart was migrated to support only helm v3 and later.
+
+### From 10.x to 11.x
+
+Version 11 upgrades prometheus-operator from 0.42.x to 0.43.x. Starting with 0.43.x an additional `AlertmanagerConfigs` CRD is introduced. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRD manually before updating:
+
+```console
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/release-0.43/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml
+```
+
+Version 11 removes the deprecated tlsProxy via ghostunnel in favor of native TLS support the prometheus-operator gained with v0.39.0.
+
+### From 9.x to 10.x
+
+Version 10 upgrades prometheus-operator from 0.38.x to 0.42.x. Starting with 0.40.x an additional `Probes` CRD is introduced. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRD manually before updating:
+
+```console
+kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/release-0.42/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml
+```
+
+### From 8.x to 9.x
+
+Version 9 of the helm chart removes the existing `additionalScrapeConfigsExternal` in favour of `additionalScrapeConfigsSecret`. This change lets users specify the secret name and secret key to use for the additional scrape configuration of prometheus. This is useful for users that have prometheus-operator as a subchart and also have a template that creates the additional scrape configuration.
+
+### From 7.x to 8.x
+
+Due to new template functions being used in the rules in version 8.x.x of the chart, an upgrade to Prometheus Operator and Prometheus is necessary in order to support them. First, upgrade to the latest version of 7.x.x
+
+```console
+helm upgrade [RELEASE_NAME] prometheus-community/kube-prometheus-stack --version 7.5.0
+```
+
+Then upgrade to 8.x.x
+
+```console
+helm upgrade [RELEASE_NAME] prometheus-community/kube-prometheus-stack --version [8.x.x]
+```
+
+Minimal recommended Prometheus version for this chart release is `2.12.x`
+
+### From 6.x to 7.x
+
+Due to a change in grafana subchart, version 7.x.x now requires Helm >= 2.12.0.
+
+### From 5.x to 6.x
+
+Due to a change in deployment labels of kube-state-metrics, the upgrade requires `helm upgrade --force` in order to re-create the deployment. If this is not done an error will occur indicating that the deployment cannot be modified:
+
+```console
+invalid: spec.selector: Invalid value: v1.LabelSelector{MatchLabels:map[string]string{"app.kubernetes.io/name":"kube-state-metrics"}, MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is immutable
+```
+
+If this error has already been encountered, a `helm history` command can be used to determine which release has worked, then `helm rollback` to the release, then `helm upgrade --force` to this new one
+
+## Configuration
+
+See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). To see all configurable options with detailed comments:
+
+```console
+helm show values prometheus-community/kube-prometheus-stack
+```
+
+You may also `helm show values` on this chart's [dependencies](#dependencies) for additional options.
+
+### Multiple releases
+
+The same chart can be used to run multiple Prometheus instances in the same cluster if required. To achieve this, it is necessary to run only one instance of prometheus-operator and a pair of alertmanager pods for an HA configuration, while all other components need to be disabled. To disable a dependency during installation, set `kubeStateMetrics.enabled`, `nodeExporter.enabled` and `grafana.enabled` to `false`.
+
+## Work-Arounds for Known Issues
+
+### Running on private GKE clusters
+
+When Google configure the control plane for private clusters, they automatically configure VPC peering between your Kubernetes cluster’s network and a separate Google managed project. In order to restrict what Google are able to access within your cluster, the firewall rules configured restrict access to your Kubernetes pods. This means that in order to use the webhook component with a GKE private cluster, you must configure an additional firewall rule to allow the GKE control plane access to your webhook pod.
+
+You can read more information on how to add firewall rules for the GKE control plane nodes in the [GKE docs](https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters#add_firewall_rules)
+
+Alternatively, you can disable the hooks by setting `prometheusOperator.admissionWebhooks.enabled=false`.
+
+## PrometheusRules Admission Webhooks
+
+With Prometheus Operator version 0.30+, the core Prometheus Operator pod exposes an endpoint that will integrate with the `validatingwebhookconfiguration` Kubernetes feature to prevent malformed rules from being added to the cluster.
+
+### How the Chart Configures the Hooks
+
+A validating and mutating webhook configuration requires the endpoint to which the request is sent to use TLS. It is possible to set up custom certificates to do this, but in most cases, a self-signed certificate is enough. The setup of this component requires some more complex orchestration when using helm. The steps are created to be idempotent and to allow turning the feature on and off without running into helm quirks.
+
+1. A pre-install hook provisions a certificate into the same namespace using a format compatible with provisioning using end user certificates. If the certificate already exists, the hook exits.
+2. The prometheus operator pod is configured to use a TLS proxy container, which will load that certificate.
+3. Validating and Mutating webhook configurations are created in the cluster, with their failure mode set to Ignore. This allows rules to be created by the same chart at the same time, even though the webhook has not yet been fully set up - it does not have the correct CA field set.
+4. A post-install hook reads the CA from the secret created by step 1 and patches the Validating and Mutating webhook configurations. This process will allow a custom CA provisioned by some other process to also be patched into the webhook configurations. The chosen failure policy is also patched into the webhook configurations
+
+### Alternatives
+
+It should be possible to use [jetstack/cert-manager](https://github.com/jetstack/cert-manager) if a more complete solution is required, but it has not been tested.
+
+You can enable automatic self-signed TLS certificate provisioning via cert-manager by setting the `prometheusOperator.admissionWebhooks.certManager.enabled` value to true.
+
+### Limitations
+
+Because the operator can only run as a single pod, there is potential for this component failure to cause rule deployment failure. Because this risk is outweighed by the benefit of having validation, the feature is enabled by default.
+
+## Developing Prometheus Rules and Grafana Dashboards
+
+This chart Grafana Dashboards and Prometheus Rules are just a copy from [prometheus-operator/prometheus-operator](https://github.com/prometheus-operator/prometheus-operator) and other sources, synced (with alterations) by scripts in [hack](hack) folder. In order to introduce any changes you need to first [add them to the original repository](https://github.com/prometheus-operator/kube-prometheus/blob/main/docs/customizations/developing-prometheus-rules-and-grafana-dashboards.md) and then sync there by scripts.
+
+## Further Information
+
+For more in-depth documentation of configuration options meanings, please see
+
+- [Prometheus Operator](https://github.com/prometheus-operator/prometheus-operator)
+- [Prometheus](https://prometheus.io/docs/introduction/overview/)
+- [Grafana](https://github.com/grafana/helm-charts/tree/main/charts/grafana#grafana-helm-chart)
+
+## prometheus.io/scrape
+
+The prometheus operator does not support annotation-based discovery of services, using the `PodMonitor` or `ServiceMonitor` CRD in its place as they provide far more configuration options.
+For information on how to use PodMonitors/ServiceMonitors, please see the documentation on the `prometheus-operator/prometheus-operator` documentation here:
+
+- [ServiceMonitors](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md#include-servicemonitors)
+- [PodMonitors](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md#include-podmonitors)
+- [Running Exporters](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/running-exporters.md)
+
+By default, Prometheus discovers PodMonitors and ServiceMonitors within its namespace, that are labeled with the same release tag as the prometheus-operator release.
+Sometimes, you may need to discover custom PodMonitors/ServiceMonitors, for example used to scrape data from third-party applications.
+An easy way of doing this, without compromising the default PodMonitors/ServiceMonitors discovery, is allowing Prometheus to discover all PodMonitors/ServiceMonitors within its namespace, without applying label filtering.
+To do so, you can set `prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues` and `prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues` to `false`.
+
+## Migrating from stable/prometheus-operator chart
+
+## Zero downtime
+
+Since `kube-prometheus-stack` is fully compatible with the `stable/prometheus-operator` chart, a migration without downtime can be achieved.
+However, the old name prefix needs to be kept. If you want the new name please follow the step by step guide below (with downtime).
+
+You can override the name to achieve this:
+
+```console
+helm upgrade prometheus-operator prometheus-community/kube-prometheus-stack -n monitoring --reuse-values --set nameOverride=prometheus-operator
+```
+
+**Note**: It is recommended to run this first with `--dry-run --debug`.
+
+## Redeploy with new name (downtime)
+
+If the **prometheus-operator** values are compatible with the new **kube-prometheus-stack** chart, please follow the below steps for migration:
+
+> The guide presumes that chart is deployed in `monitoring` namespace and the deployments are running there. If in other namespace, please replace the `monitoring` to the deployed namespace.
+
+1. Patch the PersistenceVolume created/used by the prometheus-operator chart to `Retain` claim policy:
+
+ ```console
+ kubectl patch pv/ -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
+ ```
+
+ **Note:** To execute the above command, the user must have a cluster wide permission. Please refer [Kubernetes RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)
+
+2. Uninstall the **prometheus-operator** release and delete the existing PersistentVolumeClaim, and verify PV become Released.
+
+ ```console
+ helm uninstall prometheus-operator -n monitoring
+ kubectl delete pvc/ -n monitoring
+ ```
+
+ Additionally, you have to manually remove the remaining `prometheus-operator-kubelet` service.
+
+ ```console
+ kubectl delete service/prometheus-operator-kubelet -n kube-system
+ ```
+
+ You can choose to remove all your existing CRDs (ServiceMonitors, Podmonitors, etc.) if you want to.
+
+3. Remove current `spec.claimRef` values to change the PV's status from Released to Available.
+
+ ```console
+ kubectl patch pv/ --type json -p='[{"op": "remove", "path": "/spec/claimRef"}]' -n monitoring
+ ```
+
+**Note:** To execute the above command, the user must have a cluster wide permission. Please refer to [Kubernetes RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)
+
+After these steps, proceed to a fresh **kube-prometheus-stack** installation and make sure the current release of **kube-prometheus-stack** matching the `volumeClaimTemplate` values in the `values.yaml`.
+
+The binding is done via matching a specific amount of storage requested and with certain access modes.
+
+For example, if you had storage specified as this with **prometheus-operator**:
+
+```yaml
+volumeClaimTemplate:
+ spec:
+ storageClassName: gp2
+ accessModes: ["ReadWriteOnce"]
+ resources:
+ requests:
+ storage: 50Gi
+```
+
+You have to specify matching `volumeClaimTemplate` with 50Gi storage and `ReadWriteOnce` access mode.
+
+Additionally, you should check the current AZ of your legacy installation's PV, and configure the fresh release to use the same AZ as the old one. If the pods are in a different AZ than the PV, the release will fail to bind the existing one, hence creating a new PV.
+
+This can be achieved either by specifying the labels through `values.yaml`, e.g. setting `prometheus.prometheusSpec.nodeSelector` to:
+
+```yaml
+nodeSelector:
+ failure-domain.beta.kubernetes.io/zone: east-west-1a
+```
+
+or passing these values as `--set` overrides during installation.
+
+The new release should now re-attach your previously released PV with its content.
+
+## Migrating from coreos/prometheus-operator chart
+
+The multiple charts have been combined into a single chart that installs prometheus operator, prometheus, alertmanager, grafana as well as the multitude of exporters necessary to monitor a cluster.
+
+There is no simple and direct migration path between the charts as the changes are extensive and intended to make the chart easier to support.
+
+The capabilities of the old chart are all available in the new chart, including the ability to run multiple prometheus instances on a single cluster - you will need to disable the parts of the chart you do not wish to deploy.
+
+You can check out the tickets for this change [here](https://github.com/prometheus-operator/prometheus-operator/issues/592) and [here](https://github.com/helm/charts/pull/6765).
+
+### High-level overview of Changes
+
+#### Added dependencies
+
+The chart has added 3 [dependencies](#dependencies).
+
+- Node-Exporter, Kube-State-Metrics: These components are loaded as dependencies into the chart, and are relatively simple components
+- Grafana: The Grafana chart is more feature-rich than this chart - it contains a sidecar that is able to load data sources and dashboards from configmaps deployed into the same cluster. For more information check out the [documentation for the chart](https://github.com/grafana/helm-charts/blob/main/charts/grafana/README.md)
+
+#### Kubelet Service
+
+Because the kubelet service has a new name in the chart, make sure to clean up the old kubelet service in the `kube-system` namespace to prevent counting container metrics twice.
+
+#### Persistent Volumes
+
+If you would like to keep the data of the current persistent volumes, it should be possible to attach existing volumes to new PVCs and PVs that are created using the conventions in the new chart. For example, in order to use an existing Azure disk for a helm release called `prometheus-migration` the following resources can be created:
+
+```yaml
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: pvc-prometheus-migration-prometheus-0
+spec:
+ accessModes:
+ - ReadWriteOnce
+ azureDisk:
+ cachingMode: None
+ diskName: pvc-prometheus-migration-prometheus-0
+ diskURI: /subscriptions/f5125d82-2622-4c50-8d25-3f7ba3e9ac4b/resourceGroups/sample-migration-resource-group/providers/Microsoft.Compute/disks/pvc-prometheus-migration-prometheus-0
+ fsType: ""
+ kind: Managed
+ readOnly: false
+ capacity:
+ storage: 1Gi
+ persistentVolumeReclaimPolicy: Delete
+ storageClassName: prometheus
+ volumeMode: Filesystem
+```
+
+```yaml
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ labels:
+ app.kubernetes.io/name: prometheus
+ prometheus: prometheus-migration-prometheus
+ name: prometheus-prometheus-migration-prometheus-db-prometheus-prometheus-migration-prometheus-0
+ namespace: monitoring
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+ storageClassName: prometheus
+ volumeMode: Filesystem
+ volumeName: pvc-prometheus-migration-prometheus-0
+```
+
+The PVC will take ownership of the PV and when you create a release using a persistent volume claim template it will use the existing PVCs as they match the naming convention used by the chart. For other cloud providers similar approaches can be used.
+
+#### KubeProxy
+
+The metrics bind address of kube-proxy is default to `127.0.0.1:10249` that prometheus instances **cannot** access to. You should expose metrics by changing `metricsBindAddress` field value to `0.0.0.0:10249` if you want to collect them.
+
+Depending on the cluster, the relevant part `config.conf` will be in ConfigMap `kube-system/kube-proxy` or `kube-system/kube-proxy-config`. For example:
+
+```console
+kubectl -n kube-system edit cm kube-proxy
+```
+
+```yaml
+apiVersion: v1
+data:
+ config.conf: |-
+ apiVersion: kubeproxy.config.k8s.io/v1alpha1
+ kind: KubeProxyConfiguration
+ # ...
+ # metricsBindAddress: 127.0.0.1:10249
+ metricsBindAddress: 0.0.0.0:10249
+ # ...
+ kubeconfig.conf: |-
+ # ...
+kind: ConfigMap
+metadata:
+ labels:
+ app: kube-proxy
+ name: kube-proxy
+ namespace: kube-system
+```
diff --git a/kube-prometheus-stack/default-values.yaml b/kube-prometheus-stack/default-values.yaml
new file mode 100644
index 00000000..ce3e59d6
--- /dev/null
+++ b/kube-prometheus-stack/default-values.yaml
@@ -0,0 +1,3381 @@
+# Default values for kube-prometheus-stack.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+## Provide a name in place of kube-prometheus-stack for `app:` labels
+##
+nameOverride: ""
+
+## Override the deployment namespace
+##
+namespaceOverride: ""
+
+## Provide a k8s version to auto dashboard import script example: kubeTargetVersionOverride: 1.16.6
+##
+kubeTargetVersionOverride: ""
+
+## Allow kubeVersion to be overridden while creating the ingress
+##
+kubeVersionOverride: ""
+
+## Provide a name to substitute for the full names of resources
+##
+fullnameOverride: ""
+
+## Labels to apply to all resources
+##
+commonLabels: {}
+# scmhash: abc123
+# myLabel: aakkmd
+
+## Create default rules for monitoring the cluster
+##
+defaultRules:
+ create: true
+ rules:
+ alertmanager: true
+ etcd: true
+ configReloaders: true
+ general: true
+ k8s: true
+ kubeApiserverAvailability: true
+ kubeApiserverBurnrate: true
+ kubeApiserverHistogram: true
+ kubeApiserverSlos: true
+ kubeControllerManager: true
+ kubelet: true
+ kubeProxy: true
+ kubePrometheusGeneral: true
+ kubePrometheusNodeRecording: true
+ kubernetesApps: true
+ kubernetesResources: true
+ kubernetesStorage: true
+ kubernetesSystem: true
+ kubeScheduler: true
+ kubeStateMetrics: true
+ network: true
+ node: true
+ nodeExporterAlerting: true
+ nodeExporterRecording: true
+ prometheus: true
+ prometheusOperator: true
+
+ ## Reduce app namespace alert scope
+ appNamespacesTarget: ".*"
+
+ ## Labels for default rules
+ labels: {}
+ ## Annotations for default rules
+ annotations: {}
+
+ ## Additional labels for PrometheusRule alerts
+ additionalRuleLabels: {}
+
+ ## Additional annotations for PrometheusRule alerts
+ additionalRuleAnnotations: {}
+
+ ## Prefix for runbook URLs. Use this to override the first part of the runbookURLs that is common to all rules.
+ runbookUrl: "https://runbooks.prometheus-operator.dev/runbooks"
+
+ ## Disabled PrometheusRule alerts
+ disabled: {}
+ # KubeAPIDown: true
+ # NodeRAIDDegraded: true
+
+## Deprecated way to provide custom recording or alerting rules to be deployed into the cluster.
+##
+# additionalPrometheusRules: []
+# - name: my-rule-file
+# groups:
+# - name: my_group
+# rules:
+# - record: my_record
+# expr: 100 * my_record
+
+## Provide custom recording or alerting rules to be deployed into the cluster.
+##
+additionalPrometheusRulesMap: {}
+# rule-name:
+# groups:
+# - name: my_group
+# rules:
+# - record: my_record
+# expr: 100 * my_record
+
+##
+global:
+ rbac:
+ create: true
+
+ ## Create ClusterRoles that extend the existing view, edit and admin ClusterRoles to interact with prometheus-operator CRDs
+ ## Ref: https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles
+ createAggregateClusterRoles: false
+ pspEnabled: false
+ pspAnnotations: {}
+ ## Specify pod annotations
+ ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#apparmor
+ ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp
+ ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#sysctl
+ ##
+ # seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
+ # seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
+ # apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
+
+ ## Reference to one or more secrets to be used when pulling images
+ ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
+ ##
+ imagePullSecrets: []
+ # - name: "image-pull-secret"
+ # or
+ # - "image-pull-secret"
+
+## Configuration for alertmanager
+## ref: https://prometheus.io/docs/alerting/alertmanager/
+##
+alertmanager:
+
+ ## Deploy alertmanager
+ ##
+ enabled: true
+
+ ## Annotations for Alertmanager
+ ##
+ annotations: {}
+
+ ## Api that prometheus will use to communicate with alertmanager. Possible values are v1, v2
+ ##
+ apiVersion: v2
+
+ ## Service account for Alertmanager to use.
+ ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
+ ##
+ serviceAccount:
+ create: true
+ name: ""
+ annotations: {}
+
+ ## Configure pod disruption budgets for Alertmanager
+ ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget
+ ## This configuration is immutable once created and will require the PDB to be deleted to be changed
+ ## https://github.com/kubernetes/kubernetes/issues/45398
+ ##
+ podDisruptionBudget:
+ enabled: false
+ minAvailable: 1
+ maxUnavailable: ""
+
+ ## Alertmanager configuration directives
+ ## ref: https://prometheus.io/docs/alerting/configuration/#configuration-file
+ ## https://prometheus.io/webtools/alerting/routing-tree-editor/
+ ##
+ config:
+ global:
+ resolve_timeout: 5m
+ inhibit_rules:
+ - source_matchers:
+ - 'severity = critical'
+ target_matchers:
+ - 'severity =~ warning|info'
+ equal:
+ - 'namespace'
+ - 'alertname'
+ - source_matchers:
+ - 'severity = warning'
+ target_matchers:
+ - 'severity = info'
+ equal:
+ - 'namespace'
+ - 'alertname'
+ - source_matchers:
+ - 'alertname = InfoInhibitor'
+ target_matchers:
+ - 'severity = info'
+ equal:
+ - 'namespace'
+ route:
+ group_by: ['namespace']
+ group_wait: 30s
+ group_interval: 5m
+ repeat_interval: 12h
+ receiver: 'null'
+ routes:
+ - receiver: 'null'
+ matchers:
+ - alertname =~ "InfoInhibitor|Watchdog"
+ receivers:
+ - name: 'null'
+ templates:
+ - '/etc/alertmanager/config/*.tmpl'
+
+ ## Pass the Alertmanager configuration directives through Helm's templating
+ ## engine. If the Alertmanager configuration contains Alertmanager templates,
+ ## they'll need to be properly escaped so that they are not interpreted by
+ ## Helm
+ ## ref: https://helm.sh/docs/developing_charts/#using-the-tpl-function
+ ## https://prometheus.io/docs/alerting/configuration/#tmpl_string
+ ## https://prometheus.io/docs/alerting/notifications/
+ ## https://prometheus.io/docs/alerting/notification_examples/
+ tplConfig: false
+
+ ## Alertmanager template files to format alerts
+ ## By default, templateFiles are placed in /etc/alertmanager/config/ and if
+ ## they have a .tmpl file suffix will be loaded. See config.templates above
+ ## to change, add other suffixes. If adding other suffixes, be sure to update
+ ## config.templates above to include those suffixes.
+ ## ref: https://prometheus.io/docs/alerting/notifications/
+ ## https://prometheus.io/docs/alerting/notification_examples/
+ ##
+ templateFiles: {}
+ #
+ ## An example template:
+ # template_1.tmpl: |-
+ # {{ define "cluster" }}{{ .ExternalURL | reReplaceAll ".*alertmanager\\.(.*)" "$1" }}{{ end }}
+ #
+ # {{ define "slack.myorg.text" }}
+ # {{- $root := . -}}
+ # {{ range .Alerts }}
+ # *Alert:* {{ .Annotations.summary }} - `{{ .Labels.severity }}`
+ # *Cluster:* {{ template "cluster" $root }}
+ # *Description:* {{ .Annotations.description }}
+ # *Graph:* <{{ .GeneratorURL }}|:chart_with_upwards_trend:>
+ # *Runbook:* <{{ .Annotations.runbook }}|:spiral_note_pad:>
+ # *Details:*
+ # {{ range .Labels.SortedPairs }} - *{{ .Name }}:* `{{ .Value }}`
+ # {{ end }}
+ # {{ end }}
+ # {{ end }}
+
+ ingress:
+ enabled: false
+
+ # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
+ # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
+ # ingressClassName: nginx
+
+ annotations: {}
+
+ labels: {}
+
+ ## Redirect ingress to an additional defined port on the service
+ # servicePort: 8081
+
+ ## Hosts must be provided if Ingress is enabled.
+ ##
+ hosts: []
+ # - alertmanager.domain.com
+
+ ## Paths to use for ingress rules - one path should match the alertmanagerSpec.routePrefix
+ ##
+ paths: []
+ # - /
+
+ ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched)
+ ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types
+ # pathType: ImplementationSpecific
+
+ ## TLS configuration for Alertmanager Ingress
+ ## Secret must be manually created in the namespace
+ ##
+ tls: []
+ # - secretName: alertmanager-general-tls
+ # hosts:
+ # - alertmanager.example.com
+
+ ## Configuration for Alertmanager secret
+ ##
+ secret:
+ annotations: {}
+
+ ## Configuration for creating an Ingress that will map to each Alertmanager replica service
+ ## alertmanager.servicePerReplica must be enabled
+ ##
+ ingressPerReplica:
+ enabled: false
+
+ # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
+ # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
+ # ingressClassName: nginx
+
+ annotations: {}
+ labels: {}
+
+ ## Final form of the hostname for each per replica ingress is
+ ## {{ ingressPerReplica.hostPrefix }}-{{ $replicaNumber }}.{{ ingressPerReplica.hostDomain }}
+ ##
+ ## Prefix for the per replica ingress that will have `-$replicaNumber`
+ ## appended to the end
+ hostPrefix: ""
+ ## Domain that will be used for the per replica ingress
+ hostDomain: ""
+
+ ## Paths to use for ingress rules
+ ##
+ paths: []
+ # - /
+
+ ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched)
+ ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types
+ # pathType: ImplementationSpecific
+
+ ## Secret name containing the TLS certificate for alertmanager per replica ingress
+ ## Secret must be manually created in the namespace
+ tlsSecretName: ""
+
+ ## Separated secret for each per replica Ingress. Can be used together with cert-manager
+ ##
+ tlsSecretPerReplica:
+ enabled: false
+ ## Final form of the secret for each per replica ingress is
+ ## {{ tlsSecretPerReplica.prefix }}-{{ $replicaNumber }}
+ ##
+ prefix: "alertmanager"
+
+ ## Configuration for Alertmanager service
+ ##
+ service:
+ annotations: {}
+ labels: {}
+ clusterIP: ""
+
+ ## Port for Alertmanager Service to listen on
+ ##
+ port: 9093
+ ## To be used with a proxy extraContainer port
+ ##
+ targetPort: 9093
+ ## Port to expose on each node
+ ## Only used if service.type is 'NodePort'
+ ##
+ nodePort: 30903
+ ## List of IP addresses at which the Prometheus server service is available
+ ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips
+ ##
+
+ ## Additional ports to open for Alertmanager service
+ additionalPorts: []
+ # additionalPorts:
+ # - name: authenticated
+ # port: 8081
+ # targetPort: 8081
+
+ externalIPs: []
+ loadBalancerIP: ""
+ loadBalancerSourceRanges: []
+
+ ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints
+ ##
+ externalTrafficPolicy: Cluster
+
+ ## Service type
+ ##
+ type: ClusterIP
+
+ ## Configuration for creating a separate Service for each statefulset Alertmanager replica
+ ##
+ servicePerReplica:
+ enabled: false
+ annotations: {}
+
+ ## Port for Alertmanager Service per replica to listen on
+ ##
+ port: 9093
+
+ ## To be used with a proxy extraContainer port
+ targetPort: 9093
+
+ ## Port to expose on each node
+ ## Only used if servicePerReplica.type is 'NodePort'
+ ##
+ nodePort: 30904
+
+ ## Loadbalancer source IP ranges
+ ## Only used if servicePerReplica.type is "LoadBalancer"
+ loadBalancerSourceRanges: []
+
+ ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints
+ ##
+ externalTrafficPolicy: Cluster
+
+ ## Service type
+ ##
+ type: ClusterIP
+
+ ## If true, create a serviceMonitor for alertmanager
+ ##
+ serviceMonitor:
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+ selfMonitor: true
+
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+
+ ## scheme: HTTP scheme to use for scraping. Can be used with `tlsConfig` for example if using istio mTLS.
+ scheme: ""
+
+ ## tlsConfig: TLS configuration to use when scraping the endpoint. For example if using istio mTLS.
+ ## Of type: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#tlsconfig
+ tlsConfig: {}
+
+ bearerTokenFile:
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ metricRelabelings: []
+ # - action: keep
+ # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
+ # sourceLabels: [__name__]
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ relabelings: []
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## Settings affecting alertmanagerSpec
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#alertmanagerspec
+ ##
+ alertmanagerSpec:
+ ## Standard object's metadata. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata
+ ## Metadata Labels and Annotations gets propagated to the Alertmanager pods.
+ ##
+ podMetadata: {}
+
+ ## Image of Alertmanager
+ ##
+ image:
+ repository: quay.io/prometheus/alertmanager
+ tag: v0.24.0
+ sha: ""
+
+ ## If true then the user will be responsible to provide a secret with alertmanager configuration
+ ## So when true the config part will be ignored (including templateFiles) and the one in the secret will be used
+ ##
+ useExistingSecret: false
+
+ ## Secrets is a list of Secrets in the same namespace as the Alertmanager object, which shall be mounted into the
+ ## Alertmanager Pods. The Secrets are mounted into /etc/alertmanager/secrets/.
+ ##
+ secrets: []
+
+ ## ConfigMaps is a list of ConfigMaps in the same namespace as the Alertmanager object, which shall be mounted into the Alertmanager Pods.
+ ## The ConfigMaps are mounted into /etc/alertmanager/configmaps/.
+ ##
+ configMaps: []
+
+ ## ConfigSecret is the name of a Kubernetes Secret in the same namespace as the Alertmanager object, which contains configuration for
+ ## this Alertmanager instance. Defaults to 'alertmanager-' The secret is mounted into /etc/alertmanager/config.
+ ##
+ # configSecret:
+
+ ## WebTLSConfig defines the TLS parameters for HTTPS
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#alertmanagerwebspec
+ web: {}
+
+ ## AlertmanagerConfigs to be selected to merge and configure Alertmanager with.
+ ##
+ alertmanagerConfigSelector: {}
+ ## Example which selects all alertmanagerConfig resources
+ ## with label "alertconfig" with values any of "example-config" or "example-config-2"
+ # alertmanagerConfigSelector:
+ # matchExpressions:
+ # - key: alertconfig
+ # operator: In
+ # values:
+ # - example-config
+ # - example-config-2
+ #
+ ## Example which selects all alertmanagerConfig resources with label "role" set to "example-config"
+ # alertmanagerConfigSelector:
+ # matchLabels:
+ # role: example-config
+
+ ## Namespaces to be selected for AlertmanagerConfig discovery. If nil, only check own namespace.
+ ##
+ alertmanagerConfigNamespaceSelector: {}
+ ## Example which selects all namespaces
+ ## with label "alertmanagerconfig" with values any of "example-namespace" or "example-namespace-2"
+ # alertmanagerConfigNamespaceSelector:
+ # matchExpressions:
+ # - key: alertmanagerconfig
+ # operator: In
+ # values:
+ # - example-namespace
+ # - example-namespace-2
+
+ ## Example which selects all namespaces with label "alertmanagerconfig" set to "enabled"
+ # alertmanagerConfigNamespaceSelector:
+ # matchLabels:
+ # alertmanagerconfig: enabled
+
+ ## AlermanagerConfig to be used as top level configuration
+ ##
+ alertmanagerConfiguration: {}
+ ## Example with select a global alertmanagerconfig
+ # alertmanagerConfiguration:
+ # name: global-alertmanager-Configuration
+
+ ## Define Log Format
+ # Use logfmt (default) or json logging
+ logFormat: logfmt
+
+ ## Log level for Alertmanager to be configured with.
+ ##
+ logLevel: info
+
+ ## Size is the expected size of the alertmanager cluster. The controller will eventually make the size of the
+ ## running cluster equal to the expected size.
+ replicas: 1
+
+ ## Time duration Alertmanager shall retain data for. Default is '120h', and must match the regular expression
+ ## [0-9]+(ms|s|m|h) (milliseconds seconds minutes hours).
+ ##
+ retention: 120h
+
+ ## Storage is the definition of how storage will be used by the Alertmanager instances.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/storage.md
+ ##
+ storage: {}
+ # volumeClaimTemplate:
+ # spec:
+ # storageClassName: gluster
+ # accessModes: ["ReadWriteOnce"]
+ # resources:
+ # requests:
+ # storage: 50Gi
+ # selector: {}
+
+
+ ## The external URL the Alertmanager instances will be available under. This is necessary to generate correct URLs. This is necessary if Alertmanager is not served from root of a DNS name. string false
+ ##
+ externalUrl:
+
+ ## The route prefix Alertmanager registers HTTP handlers for. This is useful, if using ExternalURL and a proxy is rewriting HTTP routes of a request, and the actual ExternalURL is still true,
+ ## but the server serves requests under a different route prefix. For example for use with kubectl proxy.
+ ##
+ routePrefix: /
+
+ ## If set to true all actions on the underlying managed objects are not going to be performed, except for delete actions.
+ ##
+ paused: false
+
+ ## Define which Nodes the Pods are scheduled on.
+ ## ref: https://kubernetes.io/docs/user-guide/node-selection/
+ ##
+ nodeSelector: {}
+
+ ## Define resources requests and limits for single Pods.
+ ## ref: https://kubernetes.io/docs/user-guide/compute-resources/
+ ##
+ resources: {}
+ # requests:
+ # memory: 400Mi
+
+ ## Pod anti-affinity can prevent the scheduler from placing Prometheus replicas on the same node.
+ ## The default value "soft" means that the scheduler should *prefer* to not schedule two replica pods onto the same node but no guarantee is provided.
+ ## The value "hard" means that the scheduler is *required* to not schedule two replica pods onto the same node.
+ ## The value "" will disable pod anti-affinity so that no anti-affinity rules will be configured.
+ ##
+ podAntiAffinity: ""
+
+ ## If anti-affinity is enabled sets the topologyKey to use for anti-affinity.
+ ## This can be changed to, for example, failure-domain.beta.kubernetes.io/zone
+ ##
+ podAntiAffinityTopologyKey: kubernetes.io/hostname
+
+ ## Assign custom affinity rules to the alertmanager instance
+ ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
+ ##
+ affinity: {}
+ # nodeAffinity:
+ # requiredDuringSchedulingIgnoredDuringExecution:
+ # nodeSelectorTerms:
+ # - matchExpressions:
+ # - key: kubernetes.io/e2e-az-name
+ # operator: In
+ # values:
+ # - e2e-az1
+ # - e2e-az2
+
+ ## If specified, the pod's tolerations.
+ ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+ ##
+ tolerations: []
+ # - key: "key"
+ # operator: "Equal"
+ # value: "value"
+ # effect: "NoSchedule"
+
+ ## If specified, the pod's topology spread constraints.
+ ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
+ ##
+ topologySpreadConstraints: []
+ # - maxSkew: 1
+ # topologyKey: topology.kubernetes.io/zone
+ # whenUnsatisfiable: DoNotSchedule
+ # labelSelector:
+ # matchLabels:
+ # app: alertmanager
+
+ ## SecurityContext holds pod-level security attributes and common container settings.
+ ## This defaults to non root user with uid 1000 and gid 2000. *v1.PodSecurityContext false
+ ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
+ ##
+ securityContext:
+ runAsGroup: 2000
+ runAsNonRoot: true
+ runAsUser: 1000
+ fsGroup: 2000
+
+ ## ListenLocal makes the Alertmanager server listen on loopback, so that it does not bind against the Pod IP.
+ ## Note this is only for the Alertmanager UI, not the gossip communication.
+ ##
+ listenLocal: false
+
+ ## Containers allows injecting additional containers. This is meant to allow adding an authentication proxy to an Alertmanager pod.
+ ##
+ containers: []
+ # containers:
+ # - name: oauth-proxy
+ # image: quay.io/oauth2-proxy/oauth2-proxy:v7.3.0
+ # args:
+ # - --upstream=http://127.0.0.1:9093
+ # - --http-address=0.0.0.0:8081
+ # - ...
+ # ports:
+ # - containerPort: 8081
+ # name: oauth-proxy
+ # protocol: TCP
+ # resources: {}
+
+ # Additional volumes on the output StatefulSet definition.
+ volumes: []
+
+ # Additional VolumeMounts on the output StatefulSet definition.
+ volumeMounts: []
+
+ ## InitContainers allows injecting additional initContainers. This is meant to allow doing some changes
+ ## (permissions, dir tree) on mounted volumes before starting prometheus
+ initContainers: []
+
+ ## Priority class assigned to the Pods
+ ##
+ priorityClassName: ""
+
+ ## AdditionalPeers allows injecting a set of additional Alertmanagers to peer with to form a highly available cluster.
+ ##
+ additionalPeers: []
+
+ ## PortName to use for Alert Manager.
+ ##
+ portName: "http-web"
+
+ ## ClusterAdvertiseAddress is the explicit address to advertise in cluster. Needs to be provided for non RFC1918 [1] (public) addresses. [1] RFC1918: https://tools.ietf.org/html/rfc1918
+ ##
+ clusterAdvertiseAddress: false
+
+ ## ForceEnableClusterMode ensures Alertmanager does not deactivate the cluster mode when running with a single replica.
+ ## Use case is e.g. spanning an Alertmanager cluster across Kubernetes clusters with a single replica in each.
+ forceEnableClusterMode: false
+
+ ## Minimum number of seconds for which a newly created pod should be ready without any of its container crashing for it to
+ ## be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).
+ minReadySeconds: 0
+
+ ## ExtraSecret can be used to store various data in an extra secret
+ ## (use it for example to store hashed basic auth credentials)
+ extraSecret:
+ ## if not set, name will be auto generated
+ # name: ""
+ annotations: {}
+ data: {}
+ # auth: |
+ # foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0
+ # someoneelse:$apr1$DMZX2Z4q$6SbQIfyuLQd.xmo/P0m2c.
+
+## Using default values from https://github.com/grafana/helm-charts/blob/main/charts/grafana/values.yaml
+##
+grafana:
+ enabled: true
+ namespaceOverride: ""
+
+ ## ForceDeployDatasources Create datasource configmap even if grafana deployment has been disabled
+ ##
+ forceDeployDatasources: false
+
+ ## ForceDeployDashboard Create dashboard configmap even if grafana deployment has been disabled
+ ##
+ forceDeployDashboards: false
+
+ ## Deploy default dashboards
+ ##
+ defaultDashboardsEnabled: true
+
+ ## Timezone for the default dashboards
+ ## Other options are: browser or a specific timezone, i.e. Europe/Luxembourg
+ ##
+ defaultDashboardsTimezone: utc
+
+ adminPassword: prom-operator
+
+ rbac:
+ ## If true, Grafana PSPs will be created
+ ##
+ pspEnabled: false
+
+ ingress:
+ ## If true, Grafana Ingress will be created
+ ##
+ enabled: false
+
+ ## IngressClassName for Grafana Ingress.
+ ## Should be provided if Ingress is enable.
+ ##
+ # ingressClassName: nginx
+
+ ## Annotations for Grafana Ingress
+ ##
+ annotations: {}
+ # kubernetes.io/ingress.class: nginx
+ # kubernetes.io/tls-acme: "true"
+
+ ## Labels to be added to the Ingress
+ ##
+ labels: {}
+
+ ## Hostnames.
+ ## Must be provided if Ingress is enable.
+ ##
+ # hosts:
+ # - grafana.domain.com
+ hosts: []
+
+ ## Path for grafana ingress
+ path: /
+
+ ## TLS configuration for grafana Ingress
+ ## Secret must be manually created in the namespace
+ ##
+ tls: []
+ # - secretName: grafana-general-tls
+ # hosts:
+ # - grafana.example.com
+
+ sidecar:
+ dashboards:
+ enabled: true
+ label: grafana_dashboard
+ labelValue: "1"
+
+ ## Annotations for Grafana dashboard configmaps
+ ##
+ annotations: {}
+ multicluster:
+ global:
+ enabled: false
+ etcd:
+ enabled: false
+ provider:
+ allowUiUpdates: false
+ datasources:
+ enabled: true
+ defaultDatasourceEnabled: true
+
+ uid: prometheus
+
+ ## URL of prometheus datasource
+ ##
+ # url: http://prometheus-stack-prometheus:9090/
+
+ # If not defined, will use prometheus.prometheusSpec.scrapeInterval or its default
+ # defaultDatasourceScrapeInterval: 15s
+
+ ## Annotations for Grafana datasource configmaps
+ ##
+ annotations: {}
+
+ ## Create datasource for each Pod of Prometheus StatefulSet;
+ ## this uses headless service `prometheus-operated` which is
+ ## created by Prometheus Operator
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/0fee93e12dc7c2ea1218f19ae25ec6b893460590/pkg/prometheus/statefulset.go#L255-L286
+ createPrometheusReplicasDatasources: false
+ label: grafana_datasource
+ labelValue: "1"
+
+ ## Field with internal link pointing to existing data source in Grafana.
+ ## Can be provisioned via additionalDataSources
+ exemplarTraceIdDestinations: {}
+ # datasourceUid: Jaeger
+ # traceIdLabelName: trace_id
+
+ extraConfigmapMounts: []
+ # - name: certs-configmap
+ # mountPath: /etc/grafana/ssl/
+ # configMap: certs-configmap
+ # readOnly: true
+
+ deleteDatasources: []
+ # - name: example-datasource
+ # orgId: 1
+
+ ## Configure additional grafana datasources (passed through tpl)
+ ## ref: http://docs.grafana.org/administration/provisioning/#datasources
+ additionalDataSources: []
+ # - name: prometheus-sample
+ # access: proxy
+ # basicAuth: true
+ # basicAuthPassword: pass
+ # basicAuthUser: daco
+ # editable: false
+ # jsonData:
+ # tlsSkipVerify: true
+ # orgId: 1
+ # type: prometheus
+ # url: https://{{ printf "%s-prometheus.svc" .Release.Name }}:9090
+ # version: 1
+
+ ## Passed to grafana subchart and used by servicemonitor below
+ ##
+ service:
+ portName: http-web
+
+ serviceMonitor:
+ # If true, a ServiceMonitor CRD is created for a prometheus operator
+ # https://github.com/coreos/prometheus-operator
+ #
+ enabled: true
+
+ # Path to use for scraping metrics. Might be different if server.root_url is set
+ # in grafana.ini
+ path: "/metrics"
+
+ # namespace: monitoring (defaults to use the namespace this chart is deployed to)
+
+ # labels for the ServiceMonitor
+ labels: {}
+
+ # Scrape interval. If not set, the Prometheus default scrape interval is used.
+ #
+ interval: ""
+ scheme: http
+ tlsConfig: {}
+ scrapeTimeout: 30s
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ relabelings: []
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+## Component scraping the kube api server
+##
+kubeApiServer:
+ enabled: true
+ tlsConfig:
+ serverName: kubernetes
+ insecureSkipVerify: false
+ serviceMonitor:
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+
+ jobLabel: component
+ selector:
+ matchLabels:
+ component: apiserver
+ provider: kubernetes
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ metricRelabelings:
+ # Drop excessively noisy apiserver buckets.
+ - action: drop
+ regex: apiserver_request_duration_seconds_bucket;(0.15|0.2|0.3|0.35|0.4|0.45|0.6|0.7|0.8|0.9|1.25|1.5|1.75|2|3|3.5|4|4.5|6|7|8|9|15|25|40|50)
+ sourceLabels:
+ - __name__
+ - le
+ # - action: keep
+ # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
+ # sourceLabels: [__name__]
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ relabelings: []
+ # - sourceLabels:
+ # - __meta_kubernetes_namespace
+ # - __meta_kubernetes_service_name
+ # - __meta_kubernetes_endpoint_port_name
+ # action: keep
+ # regex: default;kubernetes;https
+ # - targetLabel: __address__
+ # replacement: kubernetes.default.svc:443
+
+ ## Additional labels
+ ##
+ additionalLabels: {}
+ # foo: bar
+
+## Component scraping the kubelet and kubelet-hosted cAdvisor
+##
+kubelet:
+ enabled: true
+ namespace: kube-system
+
+ serviceMonitor:
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+
+ ## Enable scraping the kubelet over https. For requirements to enable this see
+ ## https://github.com/prometheus-operator/prometheus-operator/issues/926
+ ##
+ https: true
+
+ ## Enable scraping /metrics/cadvisor from kubelet's service
+ ##
+ cAdvisor: true
+
+ ## Enable scraping /metrics/probes from kubelet's service
+ ##
+ probes: true
+
+ ## Enable scraping /metrics/resource from kubelet's service
+ ## This is disabled by default because container metrics are already exposed by cAdvisor
+ ##
+ resource: false
+ # From kubernetes 1.18, /metrics/resource/v1alpha1 renamed to /metrics/resource
+ resourcePath: "/metrics/resource/v1alpha1"
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ cAdvisorMetricRelabelings:
+ # Drop less useful container CPU metrics.
+ - sourceLabels: [__name__]
+ action: drop
+ regex: 'container_cpu_(cfs_throttled_seconds_total|load_average_10s|system_seconds_total|user_seconds_total)'
+ # Drop less useful container / always zero filesystem metrics.
+ - sourceLabels: [__name__]
+ action: drop
+ regex: 'container_fs_(io_current|io_time_seconds_total|io_time_weighted_seconds_total|reads_merged_total|sector_reads_total|sector_writes_total|writes_merged_total)'
+ # Drop less useful / always zero container memory metrics.
+ - sourceLabels: [__name__]
+ action: drop
+ regex: 'container_memory_(mapped_file|swap)'
+ # Drop less useful container process metrics.
+ - sourceLabels: [__name__]
+ action: drop
+ regex: 'container_(file_descriptors|tasks_state|threads_max)'
+ # Drop container spec metrics that overlap with kube-state-metrics.
+ - sourceLabels: [__name__]
+ action: drop
+ regex: 'container_spec.*'
+ # Drop cgroup metrics with no pod.
+ - sourceLabels: [id, pod]
+ action: drop
+ regex: '.+;'
+ # - sourceLabels: [__name__, image]
+ # separator: ;
+ # regex: container_([a-z_]+);
+ # replacement: $1
+ # action: drop
+ # - sourceLabels: [__name__]
+ # separator: ;
+ # regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s)
+ # replacement: $1
+ # action: drop
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ probesMetricRelabelings: []
+ # - sourceLabels: [__name__, image]
+ # separator: ;
+ # regex: container_([a-z_]+);
+ # replacement: $1
+ # action: drop
+ # - sourceLabels: [__name__]
+ # separator: ;
+ # regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s)
+ # replacement: $1
+ # action: drop
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ ## metrics_path is required to match upstream rules and charts
+ cAdvisorRelabelings:
+ - sourceLabels: [__metrics_path__]
+ targetLabel: metrics_path
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ probesRelabelings:
+ - sourceLabels: [__metrics_path__]
+ targetLabel: metrics_path
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ resourceRelabelings:
+ - sourceLabels: [__metrics_path__]
+ targetLabel: metrics_path
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ metricRelabelings: []
+ # - sourceLabels: [__name__, image]
+ # separator: ;
+ # regex: container_([a-z_]+);
+ # replacement: $1
+ # action: drop
+ # - sourceLabels: [__name__]
+ # separator: ;
+ # regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s)
+ # replacement: $1
+ # action: drop
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ ## metrics_path is required to match upstream rules and charts
+ relabelings:
+ - sourceLabels: [__metrics_path__]
+ targetLabel: metrics_path
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## Additional labels
+ ##
+ additionalLabels: {}
+ # foo: bar
+
+## Component scraping the kube controller manager
+##
+kubeControllerManager:
+ enabled: true
+
+ ## If your kube controller manager is not deployed as a pod, specify IPs it can be found on
+ ##
+ endpoints: []
+ # - 10.141.4.22
+ # - 10.141.4.23
+ # - 10.141.4.24
+
+ ## If using kubeControllerManager.endpoints only the port and targetPort are used
+ ##
+ service:
+ enabled: true
+ ## If null or unset, the value is determined dynamically based on target Kubernetes version due to change
+ ## of default port in Kubernetes 1.22.
+ ##
+ port: null
+ targetPort: null
+ # selector:
+ # component: kube-controller-manager
+
+ serviceMonitor:
+ enabled: true
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+
+ ## Enable scraping kube-controller-manager over https.
+ ## Requires proper certs (not self-signed) and delegated authentication/authorization checks.
+ ## If null or unset, the value is determined dynamically based on target Kubernetes version.
+ ##
+ https: null
+
+ # Skip TLS certificate validation when scraping
+ insecureSkipVerify: null
+
+ # Name of the server to use when validating TLS certificate
+ serverName: null
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ metricRelabelings: []
+ # - action: keep
+ # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
+ # sourceLabels: [__name__]
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ relabelings: []
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## Additional labels
+ ##
+ additionalLabels: {}
+ # foo: bar
+
+## Component scraping coreDns. Use either this or kubeDns
+##
+coreDns:
+ enabled: true
+ service:
+ port: 9153
+ targetPort: 9153
+ # selector:
+ # k8s-app: kube-dns
+ serviceMonitor:
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ metricRelabelings: []
+ # - action: keep
+ # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
+ # sourceLabels: [__name__]
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ relabelings: []
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## Additional labels
+ ##
+ additionalLabels: {}
+ # foo: bar
+
+## Component scraping kubeDns. Use either this or coreDns
+##
+kubeDns:
+ enabled: false
+ service:
+ dnsmasq:
+ port: 10054
+ targetPort: 10054
+ skydns:
+ port: 10055
+ targetPort: 10055
+ # selector:
+ # k8s-app: kube-dns
+ serviceMonitor:
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ metricRelabelings: []
+ # - action: keep
+ # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
+ # sourceLabels: [__name__]
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ relabelings: []
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ dnsmasqMetricRelabelings: []
+ # - action: keep
+ # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
+ # sourceLabels: [__name__]
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ dnsmasqRelabelings: []
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## Additional labels
+ ##
+ additionalLabels: {}
+ # foo: bar
+
+## Component scraping etcd
+##
+kubeEtcd:
+ enabled: true
+
+ ## If your etcd is not deployed as a pod, specify IPs it can be found on
+ ##
+ endpoints: []
+ # - 10.141.4.22
+ # - 10.141.4.23
+ # - 10.141.4.24
+
+ ## Etcd service. If using kubeEtcd.endpoints only the port and targetPort are used
+ ##
+ service:
+ enabled: true
+ port: 2381
+ targetPort: 2381
+ # selector:
+ # component: etcd
+
+ ## Configure secure access to the etcd cluster by loading a secret into prometheus and
+ ## specifying security configuration below. For example, with a secret named etcd-client-cert
+ ##
+ ## serviceMonitor:
+ ## scheme: https
+ ## insecureSkipVerify: false
+ ## serverName: localhost
+ ## caFile: /etc/prometheus/secrets/etcd-client-cert/etcd-ca
+ ## certFile: /etc/prometheus/secrets/etcd-client-cert/etcd-client
+ ## keyFile: /etc/prometheus/secrets/etcd-client-cert/etcd-client-key
+ ##
+ serviceMonitor:
+ enabled: true
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+ scheme: http
+ insecureSkipVerify: false
+ serverName: ""
+ caFile: ""
+ certFile: ""
+ keyFile: ""
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ metricRelabelings: []
+ # - action: keep
+ # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
+ # sourceLabels: [__name__]
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ relabelings: []
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## Additional labels
+ ##
+ additionalLabels: {}
+ # foo: bar
+
+## Component scraping kube scheduler
+##
+kubeScheduler:
+ enabled: true
+
+ ## If your kube scheduler is not deployed as a pod, specify IPs it can be found on
+ ##
+ endpoints: []
+ # - 10.141.4.22
+ # - 10.141.4.23
+ # - 10.141.4.24
+
+ ## If using kubeScheduler.endpoints only the port and targetPort are used
+ ##
+ service:
+ enabled: true
+ ## If null or unset, the value is determined dynamically based on target Kubernetes version due to change
+ ## of default port in Kubernetes 1.23.
+ ##
+ port: null
+ targetPort: null
+ # selector:
+ # component: kube-scheduler
+
+ serviceMonitor:
+ enabled: true
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+ ## Enable scraping kube-scheduler over https.
+ ## Requires proper certs (not self-signed) and delegated authentication/authorization checks.
+ ## If null or unset, the value is determined dynamically based on target Kubernetes version.
+ ##
+ https: null
+
+ ## Skip TLS certificate validation when scraping
+ insecureSkipVerify: null
+
+ ## Name of the server to use when validating TLS certificate
+ serverName: null
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ metricRelabelings: []
+ # - action: keep
+ # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
+ # sourceLabels: [__name__]
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ relabelings: []
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## Additional labels
+ ##
+ additionalLabels: {}
+ # foo: bar
+
+## Component scraping kube proxy
+##
+kubeProxy:
+ enabled: true
+
+ ## If your kube proxy is not deployed as a pod, specify IPs it can be found on
+ ##
+ endpoints: []
+ # - 10.141.4.22
+ # - 10.141.4.23
+ # - 10.141.4.24
+
+ service:
+ enabled: true
+ port: 10249
+ targetPort: 10249
+ # selector:
+ # k8s-app: kube-proxy
+
+ serviceMonitor:
+ enabled: true
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+
+ ## Enable scraping kube-proxy over https.
+ ## Requires proper certs (not self-signed) and delegated authentication/authorization checks
+ ##
+ https: false
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ metricRelabelings: []
+ # - action: keep
+ # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
+ # sourceLabels: [__name__]
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ relabelings: []
+ # - action: keep
+ # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
+ # sourceLabels: [__name__]
+
+ ## Additional labels
+ ##
+ additionalLabels: {}
+ # foo: bar
+
+## Component scraping kube state metrics
+##
+kubeStateMetrics:
+ enabled: true
+
+## Configuration for kube-state-metrics subchart
+##
+kube-state-metrics:
+ namespaceOverride: ""
+ rbac:
+ create: true
+ releaseLabel: true
+ prometheus:
+ monitor:
+ enabled: true
+
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+
+ ## Scrape Timeout. If not set, the Prometheus default scrape timeout is used.
+ ##
+ scrapeTimeout: ""
+
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+
+ # Keep labels from scraped data, overriding server-side labels
+ ##
+ honorLabels: true
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ metricRelabelings: []
+ # - action: keep
+ # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
+ # sourceLabels: [__name__]
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ relabelings: []
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ selfMonitor:
+ enabled: false
+
+## Deploy node exporter as a daemonset to all nodes
+##
+nodeExporter:
+ enabled: true
+
+## Configuration for prometheus-node-exporter subchart
+##
+prometheus-node-exporter:
+ namespaceOverride: ""
+ podLabels:
+ ## Add the 'node-exporter' label to be used by serviceMonitor to match standard common usage in rules and grafana dashboards
+ ##
+ jobLabel: node-exporter
+ releaseLabel: true
+ extraArgs:
+ - --collector.filesystem.mount-points-exclude=^/(dev|proc|sys|var/lib/docker/.+|var/lib/kubelet/.+)($|/)
+ - --collector.filesystem.fs-types-exclude=^(autofs|binfmt_misc|bpf|cgroup2?|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|iso9660|mqueue|nsfs|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|selinuxfs|squashfs|sysfs|tracefs)$
+ service:
+ portName: http-metrics
+ prometheus:
+ monitor:
+ enabled: true
+
+ jobLabel: jobLabel
+
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+
+ ## How long until a scrape request times out. If not set, the Prometheus default scape timeout is used.
+ ##
+ scrapeTimeout: ""
+
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ metricRelabelings: []
+ # - sourceLabels: [__name__]
+ # separator: ;
+ # regex: ^node_mountstats_nfs_(event|operations|transport)_.+
+ # replacement: $1
+ # action: drop
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ relabelings: []
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+ rbac:
+ ## If true, create PSPs for node-exporter
+ ##
+ pspEnabled: false
+
+## Manages Prometheus and Alertmanager components
+##
+prometheusOperator:
+ enabled: true
+
+ ## Prometheus-Operator v0.39.0 and later support TLS natively.
+ ##
+ tls:
+ enabled: true
+ # Value must match version names from https://golang.org/pkg/crypto/tls/#pkg-constants
+ tlsMinVersion: VersionTLS13
+ # The default webhook port is 10250 in order to work out-of-the-box in GKE private clusters and avoid adding firewall rules.
+ internalPort: 10250
+
+ ## Admission webhook support for PrometheusRules resources added in Prometheus Operator 0.30 can be enabled to prevent incorrectly formatted
+ ## rules from making their way into prometheus and potentially preventing the container from starting
+ admissionWebhooks:
+ failurePolicy: Fail
+ ## The default timeoutSeconds is 10 and the maximum value is 30.
+ timeoutSeconds: 10
+ enabled: true
+ ## A PEM encoded CA bundle which will be used to validate the webhook's server certificate.
+ ## If unspecified, system trust roots on the apiserver are used.
+ caBundle: ""
+ ## If enabled, generate a self-signed certificate, then patch the webhook configurations with the generated data.
+ ## On chart upgrades (or if the secret exists) the cert will not be re-generated. You can use this to provide your own
+ ## certs ahead of time if you wish.
+ ##
+ patch:
+ enabled: true
+ image:
+ repository: k8s.gcr.io/ingress-nginx/kube-webhook-certgen
+ tag: v1.3.0
+ sha: ""
+ pullPolicy: IfNotPresent
+ resources: {}
+ ## Provide a priority class name to the webhook patching job
+ ##
+ priorityClassName: ""
+ podAnnotations: {}
+ nodeSelector: {}
+ affinity: {}
+ tolerations: []
+
+ ## SecurityContext holds pod-level security attributes and common container settings.
+ ## This defaults to non root user with uid 2000 and gid 2000. *v1.PodSecurityContext false
+ ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
+ ##
+ securityContext:
+ runAsGroup: 2000
+ runAsNonRoot: true
+ runAsUser: 2000
+
+ # Security context for create job container
+ createSecretJob:
+ securityContext: {}
+
+ # Security context for patch job container
+ patchWebhookJob:
+ securityContext: {}
+
+ # Use certmanager to generate webhook certs
+ certManager:
+ enabled: false
+ # self-signed root certificate
+ rootCert:
+ duration: "" # default to be 5y
+ admissionCert:
+ duration: "" # default to be 1y
+ # issuerRef:
+ # name: "issuer"
+ # kind: "ClusterIssuer"
+
+ ## Namespaces to scope the interaction of the Prometheus Operator and the apiserver (allow list).
+ ## This is mutually exclusive with denyNamespaces. Setting this to an empty object will disable the configuration
+ ##
+ namespaces: {}
+ # releaseNamespace: true
+ # additional:
+ # - kube-system
+
+ ## Namespaces not to scope the interaction of the Prometheus Operator (deny list).
+ ##
+ denyNamespaces: []
+
+ ## Filter namespaces to look for prometheus-operator custom resources
+ ##
+ alertmanagerInstanceNamespaces: []
+ alertmanagerConfigNamespaces: []
+ prometheusInstanceNamespaces: []
+ thanosRulerInstanceNamespaces: []
+
+ ## The clusterDomain value will be added to the cluster.peer option of the alertmanager.
+ ## Without this specified option cluster.peer will have value alertmanager-monitoring-alertmanager-0.alertmanager-operated:9094 (default value)
+ ## With this specified option cluster.peer will have value alertmanager-monitoring-alertmanager-0.alertmanager-operated.namespace.svc.cluster-domain:9094
+ ##
+ # clusterDomain: "cluster.local"
+
+ ## Service account for Alertmanager to use.
+ ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
+ ##
+ serviceAccount:
+ create: true
+ name: ""
+
+ ## Configuration for Prometheus operator service
+ ##
+ service:
+ annotations: {}
+ labels: {}
+ clusterIP: ""
+
+ ## Port to expose on each node
+ ## Only used if service.type is 'NodePort'
+ ##
+ nodePort: 30080
+
+ nodePortTls: 30443
+
+ ## Additional ports to open for Prometheus service
+ ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#multi-port-services
+ ##
+ additionalPorts: []
+
+ ## Loadbalancer IP
+ ## Only use if service.type is "LoadBalancer"
+ ##
+ loadBalancerIP: ""
+ loadBalancerSourceRanges: []
+
+ ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints
+ ##
+ externalTrafficPolicy: Cluster
+
+ ## Service type
+ ## NodePort, ClusterIP, LoadBalancer
+ ##
+ type: ClusterIP
+
+ ## List of IP addresses at which the Prometheus server service is available
+ ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips
+ ##
+ externalIPs: []
+
+ # ## Labels to add to the operator deployment
+ # ##
+ labels: {}
+
+ ## Annotations to add to the operator deployment
+ ##
+ annotations: {}
+
+ ## Labels to add to the operator pod
+ ##
+ podLabels: {}
+
+ ## Annotations to add to the operator pod
+ ##
+ podAnnotations: {}
+
+ ## Assign a PriorityClassName to pods if set
+ # priorityClassName: ""
+
+ ## Define Log Format
+ # Use logfmt (default) or json logging
+ # logFormat: logfmt
+
+ ## Decrease log verbosity to errors only
+ # logLevel: error
+
+ ## If true, the operator will create and maintain a service for scraping kubelets
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/helm/prometheus-operator/README.md
+ ##
+ kubeletService:
+ enabled: true
+ namespace: kube-system
+ ## Use '{{ template "kube-prometheus-stack.fullname" . }}-kubelet' by default
+ name: ""
+
+ ## Create a servicemonitor for the operator
+ ##
+ serviceMonitor:
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+ ## Scrape timeout. If not set, the Prometheus default scrape timeout is used.
+ scrapeTimeout: ""
+ selfMonitor: true
+
+ ## 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: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## Resource limits & requests
+ ##
+ resources: {}
+ # limits:
+ # cpu: 200m
+ # memory: 200Mi
+ # requests:
+ # cpu: 100m
+ # memory: 100Mi
+
+ # Required for use in managed kubernetes clusters (such as AWS EKS) with custom CNI (such as calico),
+ # because control-plane managed by AWS cannot communicate with pods' IP CIDR and admission webhooks are not working
+ ##
+ hostNetwork: false
+
+ ## Define which Nodes the Pods are scheduled on.
+ ## ref: https://kubernetes.io/docs/user-guide/node-selection/
+ ##
+ nodeSelector: {}
+
+ ## Tolerations for use with node taints
+ ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+ ##
+ tolerations: []
+ # - key: "key"
+ # operator: "Equal"
+ # value: "value"
+ # effect: "NoSchedule"
+
+ ## Assign custom affinity rules to the prometheus operator
+ ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
+ ##
+ affinity: {}
+ # nodeAffinity:
+ # requiredDuringSchedulingIgnoredDuringExecution:
+ # nodeSelectorTerms:
+ # - matchExpressions:
+ # - key: kubernetes.io/e2e-az-name
+ # operator: In
+ # values:
+ # - e2e-az1
+ # - e2e-az2
+ dnsConfig: {}
+ # nameservers:
+ # - 1.2.3.4
+ # searches:
+ # - ns1.svc.cluster-domain.example
+ # - my.dns.search.suffix
+ # options:
+ # - name: ndots
+ # value: "2"
+ # - name: edns0
+ securityContext:
+ fsGroup: 65534
+ runAsGroup: 65534
+ runAsNonRoot: true
+ runAsUser: 65534
+
+ ## Container-specific security context configuration
+ ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
+ ##
+ containerSecurityContext:
+ allowPrivilegeEscalation: false
+ readOnlyRootFilesystem: true
+
+ ## Prometheus-operator image
+ ##
+ image:
+ repository: quay.io/prometheus-operator/prometheus-operator
+ tag: v0.59.2
+ sha: ""
+ pullPolicy: IfNotPresent
+
+ ## Prometheus image to use for prometheuses managed by the operator
+ ##
+ # prometheusDefaultBaseImage: quay.io/prometheus/prometheus
+
+ ## Alertmanager image to use for alertmanagers managed by the operator
+ ##
+ # alertmanagerDefaultBaseImage: quay.io/prometheus/alertmanager
+
+ ## Prometheus-config-reloader
+ ##
+ prometheusConfigReloader:
+ image:
+ repository: quay.io/prometheus-operator/prometheus-config-reloader
+ tag: v0.59.2
+ sha: ""
+
+ # resource config for prometheusConfigReloader
+ resources:
+ requests:
+ cpu: 200m
+ memory: 50Mi
+ limits:
+ cpu: 200m
+ memory: 50Mi
+
+ ## Thanos side-car image when configured
+ ##
+ thanosImage:
+ repository: quay.io/thanos/thanos
+ tag: v0.28.0
+ sha: ""
+
+ ## Set a Field Selector to filter watched secrets
+ ##
+ secretFieldSelector: ""
+
+## Deploy a Prometheus instance
+##
+prometheus:
+
+ enabled: true
+
+ ## Annotations for Prometheus
+ ##
+ annotations: {}
+
+ ## Service account for Prometheuses to use.
+ ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
+ ##
+ serviceAccount:
+ create: true
+ name: ""
+ annotations: {}
+
+ # Service for thanos service discovery on sidecar
+ # Enable this can make Thanos Query can use
+ # `--store=dnssrv+_grpc._tcp.${kube-prometheus-stack.fullname}-thanos-discovery.${namespace}.svc.cluster.local` to discovery
+ # Thanos sidecar on prometheus nodes
+ # (Please remember to change ${kube-prometheus-stack.fullname} and ${namespace}. Not just copy and paste!)
+ thanosService:
+ enabled: false
+ annotations: {}
+ labels: {}
+
+ ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints
+ ##
+ externalTrafficPolicy: Cluster
+
+ ## Service type
+ ##
+ type: ClusterIP
+
+ ## gRPC port config
+ portName: grpc
+ port: 10901
+ targetPort: "grpc"
+
+ ## HTTP port config (for metrics)
+ httpPortName: http
+ httpPort: 10902
+ targetHttpPort: "http"
+
+ ## ClusterIP to assign
+ # Default is to make this a headless service ("None")
+ clusterIP: "None"
+
+ ## Port to expose on each node, if service type is NodePort
+ ##
+ nodePort: 30901
+ httpNodePort: 30902
+
+ # ServiceMonitor to scrape Sidecar metrics
+ # Needs thanosService to be enabled as well
+ thanosServiceMonitor:
+ enabled: false
+ interval: ""
+
+ ## scheme: HTTP scheme to use for scraping. Can be used with `tlsConfig` for example if using istio mTLS.
+ scheme: ""
+
+ ## tlsConfig: TLS configuration to use when scraping the endpoint. For example if using istio mTLS.
+ ## Of type: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#tlsconfig
+ tlsConfig: {}
+
+ bearerTokenFile:
+
+ ## Metric relabel configs to apply to samples before ingestion.
+ metricRelabelings: []
+
+ ## relabel configs to apply to samples before ingestion.
+ relabelings: []
+
+ # Service for external access to sidecar
+ # Enabling this creates a service to expose thanos-sidecar outside the cluster.
+ thanosServiceExternal:
+ enabled: false
+ annotations: {}
+ labels: {}
+ loadBalancerIP: ""
+ loadBalancerSourceRanges: []
+
+ ## gRPC port config
+ portName: grpc
+ port: 10901
+ targetPort: "grpc"
+
+ ## HTTP port config (for metrics)
+ httpPortName: http
+ httpPort: 10902
+ targetHttpPort: "http"
+
+ ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints
+ ##
+ externalTrafficPolicy: Cluster
+
+ ## Service type
+ ##
+ type: LoadBalancer
+
+ ## Port to expose on each node
+ ##
+ nodePort: 30901
+ httpNodePort: 30902
+
+ ## Configuration for Prometheus service
+ ##
+ service:
+ annotations: {}
+ labels: {}
+ clusterIP: ""
+
+ ## Port for Prometheus Service to listen on
+ ##
+ port: 9090
+
+ ## To be used with a proxy extraContainer port
+ targetPort: 9090
+
+ ## List of IP addresses at which the Prometheus server service is available
+ ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips
+ ##
+ externalIPs: []
+
+ ## Port to expose on each node
+ ## Only used if service.type is 'NodePort'
+ ##
+ nodePort: 30090
+
+ ## Loadbalancer IP
+ ## Only use if service.type is "LoadBalancer"
+ loadBalancerIP: ""
+ loadBalancerSourceRanges: []
+
+ ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints
+ ##
+ externalTrafficPolicy: Cluster
+
+ ## Service type
+ ##
+ type: ClusterIP
+
+ ## Additional port to define in the Service
+ additionalPorts: []
+ # additionalPorts:
+ # - name: authenticated
+ # port: 8081
+ # targetPort: 8081
+
+ ## Consider that all endpoints are considered "ready" even if the Pods themselves are not
+ ## Ref: https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/#ServiceSpec
+ publishNotReadyAddresses: false
+
+ sessionAffinity: ""
+
+ ## Configuration for creating a separate Service for each statefulset Prometheus replica
+ ##
+ servicePerReplica:
+ enabled: false
+ annotations: {}
+
+ ## Port for Prometheus Service per replica to listen on
+ ##
+ port: 9090
+
+ ## To be used with a proxy extraContainer port
+ targetPort: 9090
+
+ ## Port to expose on each node
+ ## Only used if servicePerReplica.type is 'NodePort'
+ ##
+ nodePort: 30091
+
+ ## Loadbalancer source IP ranges
+ ## Only used if servicePerReplica.type is "LoadBalancer"
+ loadBalancerSourceRanges: []
+
+ ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints
+ ##
+ externalTrafficPolicy: Cluster
+
+ ## Service type
+ ##
+ type: ClusterIP
+
+ ## Configure pod disruption budgets for Prometheus
+ ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget
+ ## This configuration is immutable once created and will require the PDB to be deleted to be changed
+ ## https://github.com/kubernetes/kubernetes/issues/45398
+ ##
+ podDisruptionBudget:
+ enabled: false
+ minAvailable: 1
+ maxUnavailable: ""
+
+ # Ingress exposes thanos sidecar outside the cluster
+ thanosIngress:
+ enabled: false
+
+ # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
+ # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
+ # ingressClassName: nginx
+
+ annotations: {}
+ labels: {}
+ servicePort: 10901
+
+ ## Port to expose on each node
+ ## Only used if service.type is 'NodePort'
+ ##
+ nodePort: 30901
+
+ ## Hosts must be provided if Ingress is enabled.
+ ##
+ hosts: []
+ # - thanos-gateway.domain.com
+
+ ## Paths to use for ingress rules
+ ##
+ paths: []
+ # - /
+
+ ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched)
+ ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types
+ # pathType: ImplementationSpecific
+
+ ## TLS configuration for Thanos Ingress
+ ## Secret must be manually created in the namespace
+ ##
+ tls: []
+ # - secretName: thanos-gateway-tls
+ # hosts:
+ # - thanos-gateway.domain.com
+ #
+
+ ## ExtraSecret can be used to store various data in an extra secret
+ ## (use it for example to store hashed basic auth credentials)
+ extraSecret:
+ ## if not set, name will be auto generated
+ # name: ""
+ annotations: {}
+ data: {}
+ # auth: |
+ # foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0
+ # someoneelse:$apr1$DMZX2Z4q$6SbQIfyuLQd.xmo/P0m2c.
+
+ ingress:
+ enabled: false
+
+ # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
+ # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
+ # ingressClassName: nginx
+
+ annotations: {}
+ labels: {}
+
+ ## Redirect ingress to an additional defined port on the service
+ # servicePort: 8081
+
+ ## Hostnames.
+ ## Must be provided if Ingress is enabled.
+ ##
+ # hosts:
+ # - prometheus.domain.com
+ hosts: []
+
+ ## Paths to use for ingress rules - one path should match the prometheusSpec.routePrefix
+ ##
+ paths: []
+ # - /
+
+ ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched)
+ ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types
+ # pathType: ImplementationSpecific
+
+ ## TLS configuration for Prometheus Ingress
+ ## Secret must be manually created in the namespace
+ ##
+ tls: []
+ # - secretName: prometheus-general-tls
+ # hosts:
+ # - prometheus.example.com
+
+ ## Configuration for creating an Ingress that will map to each Prometheus replica service
+ ## prometheus.servicePerReplica must be enabled
+ ##
+ ingressPerReplica:
+ enabled: false
+
+ # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
+ # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
+ # ingressClassName: nginx
+
+ annotations: {}
+ labels: {}
+
+ ## Final form of the hostname for each per replica ingress is
+ ## {{ ingressPerReplica.hostPrefix }}-{{ $replicaNumber }}.{{ ingressPerReplica.hostDomain }}
+ ##
+ ## Prefix for the per replica ingress that will have `-$replicaNumber`
+ ## appended to the end
+ hostPrefix: ""
+ ## Domain that will be used for the per replica ingress
+ hostDomain: ""
+
+ ## Paths to use for ingress rules
+ ##
+ paths: []
+ # - /
+
+ ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched)
+ ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types
+ # pathType: ImplementationSpecific
+
+ ## Secret name containing the TLS certificate for Prometheus per replica ingress
+ ## Secret must be manually created in the namespace
+ tlsSecretName: ""
+
+ ## Separated secret for each per replica Ingress. Can be used together with cert-manager
+ ##
+ tlsSecretPerReplica:
+ enabled: false
+ ## Final form of the secret for each per replica ingress is
+ ## {{ tlsSecretPerReplica.prefix }}-{{ $replicaNumber }}
+ ##
+ prefix: "prometheus"
+
+ ## Configure additional options for default pod security policy for Prometheus
+ ## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/
+ podSecurityPolicy:
+ allowedCapabilities: []
+ allowedHostPaths: []
+ volumes: []
+
+ serviceMonitor:
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+ selfMonitor: true
+
+ ## scheme: HTTP scheme to use for scraping. Can be used with `tlsConfig` for example if using istio mTLS.
+ scheme: ""
+
+ ## tlsConfig: TLS configuration to use when scraping the endpoint. For example if using istio mTLS.
+ ## Of type: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#tlsconfig
+ tlsConfig: {}
+
+ bearerTokenFile:
+
+ ## 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: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## Settings affecting prometheusSpec
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#prometheusspec
+ ##
+ prometheusSpec:
+ ## If true, pass --storage.tsdb.max-block-duration=2h to prometheus. This is already done if using Thanos
+ ##
+ disableCompaction: false
+ ## APIServerConfig
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#apiserverconfig
+ ##
+ apiserverConfig: {}
+
+ ## Interval between consecutive scrapes.
+ ## Defaults to 30s.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/release-0.44/pkg/prometheus/promcfg.go#L180-L183
+ ##
+ scrapeInterval: ""
+
+ ## Number of seconds to wait for target to respond before erroring
+ ##
+ scrapeTimeout: ""
+
+ ## Interval between consecutive evaluations.
+ ##
+ evaluationInterval: ""
+
+ ## ListenLocal makes the Prometheus server listen on loopback, so that it does not bind against the Pod IP.
+ ##
+ listenLocal: false
+
+ ## EnableAdminAPI enables Prometheus the administrative HTTP API which includes functionality such as deleting time series.
+ ## This is disabled by default.
+ ## ref: https://prometheus.io/docs/prometheus/latest/querying/api/#tsdb-admin-apis
+ ##
+ enableAdminAPI: false
+
+ ## WebTLSConfig defines the TLS parameters for HTTPS
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#webtlsconfig
+ web: {}
+
+ ## Exemplars related settings that are runtime reloadable.
+ ## It requires to enable the exemplar storage feature to be effective.
+ exemplars: ""
+ ## Maximum number of exemplars stored in memory for all series.
+ ## If not set, Prometheus uses its default value.
+ ## A value of zero or less than zero disables the storage.
+ # maxSize: 100000
+
+ # EnableFeatures API enables access to Prometheus disabled features.
+ # ref: https://prometheus.io/docs/prometheus/latest/disabled_features/
+ enableFeatures: []
+ # - exemplar-storage
+
+ ## Image of Prometheus.
+ ##
+ image:
+ repository: quay.io/prometheus/prometheus
+ tag: v2.38.0
+ sha: ""
+
+ ## Tolerations for use with node taints
+ ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+ ##
+ tolerations: []
+ # - key: "key"
+ # operator: "Equal"
+ # value: "value"
+ # effect: "NoSchedule"
+
+ ## If specified, the pod's topology spread constraints.
+ ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
+ ##
+ topologySpreadConstraints: []
+ # - maxSkew: 1
+ # topologyKey: topology.kubernetes.io/zone
+ # whenUnsatisfiable: DoNotSchedule
+ # labelSelector:
+ # matchLabels:
+ # app: prometheus
+
+ ## Alertmanagers to which alerts will be sent
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#alertmanagerendpoints
+ ##
+ ## Default configuration will connect to the alertmanager deployed as part of this release
+ ##
+ alertingEndpoints: []
+ # - name: ""
+ # namespace: ""
+ # port: http
+ # scheme: http
+ # pathPrefix: ""
+ # tlsConfig: {}
+ # bearerTokenFile: ""
+ # apiVersion: v2
+
+ ## External labels to add to any time series or alerts when communicating with external systems
+ ##
+ externalLabels: {}
+
+ ## enable --web.enable-remote-write-receiver flag on prometheus-server
+ ##
+ enableRemoteWriteReceiver: false
+
+ ## Name of the external label used to denote replica name
+ ##
+ replicaExternalLabelName: ""
+
+ ## If true, the Operator won't add the external label used to denote replica name
+ ##
+ replicaExternalLabelNameClear: false
+
+ ## Name of the external label used to denote Prometheus instance name
+ ##
+ prometheusExternalLabelName: ""
+
+ ## If true, the Operator won't add the external label used to denote Prometheus instance name
+ ##
+ prometheusExternalLabelNameClear: false
+
+ ## External URL at which Prometheus will be reachable.
+ ##
+ externalUrl: ""
+
+ ## Define which Nodes the Pods are scheduled on.
+ ## ref: https://kubernetes.io/docs/user-guide/node-selection/
+ ##
+ nodeSelector: {}
+
+ ## Secrets is a list of Secrets in the same namespace as the Prometheus object, which shall be mounted into the Prometheus Pods.
+ ## The Secrets are mounted into /etc/prometheus/secrets/. Secrets changes after initial creation of a Prometheus object are not
+ ## reflected in the running Pods. To change the secrets mounted into the Prometheus Pods, the object must be deleted and recreated
+ ## with the new list of secrets.
+ ##
+ secrets: []
+
+ ## ConfigMaps is a list of ConfigMaps in the same namespace as the Prometheus object, which shall be mounted into the Prometheus Pods.
+ ## The ConfigMaps are mounted into /etc/prometheus/configmaps/.
+ ##
+ configMaps: []
+
+ ## QuerySpec defines the query command line flags when starting Prometheus.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#queryspec
+ ##
+ query: {}
+
+ ## Namespaces to be selected for PrometheusRules discovery.
+ ## If nil, select own namespace. Namespaces to be selected for ServiceMonitor discovery.
+ ## See https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#namespaceselector for usage
+ ##
+ ruleNamespaceSelector: {}
+
+ ## If true, a nil or {} value for prometheus.prometheusSpec.ruleSelector will cause the
+ ## prometheus resource to be created with selectors based on values in the helm deployment,
+ ## which will also match the PrometheusRule resources created
+ ##
+ ruleSelectorNilUsesHelmValues: true
+
+ ## PrometheusRules to be selected for target discovery.
+ ## If {}, select all PrometheusRules
+ ##
+ ruleSelector: {}
+ ## Example which select all PrometheusRules resources
+ ## with label "prometheus" with values any of "example-rules" or "example-rules-2"
+ # ruleSelector:
+ # matchExpressions:
+ # - key: prometheus
+ # operator: In
+ # values:
+ # - example-rules
+ # - example-rules-2
+ #
+ ## Example which select all PrometheusRules resources with label "role" set to "example-rules"
+ # ruleSelector:
+ # matchLabels:
+ # role: example-rules
+
+ ## If true, a nil or {} value for prometheus.prometheusSpec.serviceMonitorSelector will cause the
+ ## prometheus resource to be created with selectors based on values in the helm deployment,
+ ## which will also match the servicemonitors created
+ ##
+ serviceMonitorSelectorNilUsesHelmValues: true
+
+ ## ServiceMonitors to be selected for target discovery.
+ ## If {}, select all ServiceMonitors
+ ##
+ serviceMonitorSelector: {}
+ ## Example which selects ServiceMonitors with label "prometheus" set to "somelabel"
+ # serviceMonitorSelector:
+ # matchLabels:
+ # prometheus: somelabel
+
+ ## Namespaces to be selected for ServiceMonitor discovery.
+ ##
+ serviceMonitorNamespaceSelector: {}
+ ## Example which selects ServiceMonitors in namespaces with label "prometheus" set to "somelabel"
+ # serviceMonitorNamespaceSelector:
+ # matchLabels:
+ # prometheus: somelabel
+
+ ## If true, a nil or {} value for prometheus.prometheusSpec.podMonitorSelector will cause the
+ ## prometheus resource to be created with selectors based on values in the helm deployment,
+ ## which will also match the podmonitors created
+ ##
+ podMonitorSelectorNilUsesHelmValues: true
+
+ ## PodMonitors to be selected for target discovery.
+ ## If {}, select all PodMonitors
+ ##
+ podMonitorSelector: {}
+ ## Example which selects PodMonitors with label "prometheus" set to "somelabel"
+ # podMonitorSelector:
+ # matchLabels:
+ # prometheus: somelabel
+
+ ## Namespaces to be selected for PodMonitor discovery.
+ ## See https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#namespaceselector for usage
+ ##
+ podMonitorNamespaceSelector: {}
+
+ ## If true, a nil or {} value for prometheus.prometheusSpec.probeSelector will cause the
+ ## prometheus resource to be created with selectors based on values in the helm deployment,
+ ## which will also match the probes created
+ ##
+ probeSelectorNilUsesHelmValues: true
+
+ ## Probes to be selected for target discovery.
+ ## If {}, select all Probes
+ ##
+ probeSelector: {}
+ ## Example which selects Probes with label "prometheus" set to "somelabel"
+ # probeSelector:
+ # matchLabels:
+ # prometheus: somelabel
+
+ ## Namespaces to be selected for Probe discovery.
+ ## See https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#namespaceselector for usage
+ ##
+ probeNamespaceSelector: {}
+
+ ## How long to retain metrics
+ ##
+ retention: 10d
+
+ ## Maximum size of metrics
+ ##
+ retentionSize: ""
+
+ ## Enable compression of the write-ahead log using Snappy.
+ ##
+ walCompression: true
+
+ ## If true, the Operator won't process any Prometheus configuration changes
+ ##
+ paused: false
+
+ ## Number of replicas of each shard to deploy for a Prometheus deployment.
+ ## Number of replicas multiplied by shards is the total number of Pods created.
+ ##
+ replicas: 1
+
+ ## EXPERIMENTAL: Number of shards to distribute targets onto.
+ ## Number of replicas multiplied by shards is the total number of Pods created.
+ ## Note that scaling down shards will not reshard data onto remaining instances, it must be manually moved.
+ ## Increasing shards will not reshard data either but it will continue to be available from the same instances.
+ ## To query globally use Thanos sidecar and Thanos querier or remote write data to a central location.
+ ## Sharding is done on the content of the `__address__` target meta-label.
+ ##
+ shards: 1
+
+ ## Log level for Prometheus be configured in
+ ##
+ logLevel: info
+
+ ## Log format for Prometheus be configured in
+ ##
+ logFormat: logfmt
+
+ ## Prefix used to register routes, overriding externalUrl route.
+ ## Useful for proxies that rewrite URLs.
+ ##
+ routePrefix: /
+
+ ## Standard object's metadata. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata
+ ## Metadata Labels and Annotations gets propagated to the prometheus pods.
+ ##
+ podMetadata: {}
+ # labels:
+ # app: prometheus
+ # k8s-app: prometheus
+
+ ## Pod anti-affinity can prevent the scheduler from placing Prometheus replicas on the same node.
+ ## The default value "soft" means that the scheduler should *prefer* to not schedule two replica pods onto the same node but no guarantee is provided.
+ ## The value "hard" means that the scheduler is *required* to not schedule two replica pods onto the same node.
+ ## The value "" will disable pod anti-affinity so that no anti-affinity rules will be configured.
+ podAntiAffinity: ""
+
+ ## If anti-affinity is enabled sets the topologyKey to use for anti-affinity.
+ ## This can be changed to, for example, failure-domain.beta.kubernetes.io/zone
+ ##
+ podAntiAffinityTopologyKey: kubernetes.io/hostname
+
+ ## Assign custom affinity rules to the prometheus instance
+ ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
+ ##
+ affinity: {}
+ # nodeAffinity:
+ # requiredDuringSchedulingIgnoredDuringExecution:
+ # nodeSelectorTerms:
+ # - matchExpressions:
+ # - key: kubernetes.io/e2e-az-name
+ # operator: In
+ # values:
+ # - e2e-az1
+ # - e2e-az2
+
+ ## The remote_read spec configuration for Prometheus.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#remotereadspec
+ remoteRead: []
+ # - url: http://remote1/read
+ ## additionalRemoteRead is appended to remoteRead
+ additionalRemoteRead: []
+
+ ## The remote_write spec configuration for Prometheus.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#remotewritespec
+ remoteWrite: []
+ # - url: http://remote1/push
+ ## additionalRemoteWrite is appended to remoteWrite
+ additionalRemoteWrite: []
+
+ ## Enable/Disable Grafana dashboards provisioning for prometheus remote write feature
+ remoteWriteDashboards: false
+
+ ## Resource limits & requests
+ ##
+ resources: {}
+ # requests:
+ # memory: 400Mi
+
+ ## Prometheus StorageSpec for persistent data
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/storage.md
+ ##
+ storageSpec: {}
+ ## Using PersistentVolumeClaim
+ ##
+ # volumeClaimTemplate:
+ # spec:
+ # storageClassName: gluster
+ # accessModes: ["ReadWriteOnce"]
+ # resources:
+ # requests:
+ # storage: 50Gi
+ # selector: {}
+
+ ## Using tmpfs volume
+ ##
+ # emptyDir:
+ # medium: Memory
+
+ # Additional volumes on the output StatefulSet definition.
+ volumes: []
+
+ # Additional VolumeMounts on the output StatefulSet definition.
+ volumeMounts: []
+
+ ## AdditionalScrapeConfigs allows specifying additional Prometheus scrape configurations. Scrape configurations
+ ## are appended to the configurations generated by the Prometheus Operator. Job configurations must have the form
+ ## as specified in the official Prometheus documentation:
+ ## https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config. As scrape configs are
+ ## appended, the user is responsible to make sure it is valid. Note that using this feature may expose the possibility
+ ## to break upgrades of Prometheus. It is advised to review Prometheus release notes to ensure that no incompatible
+ ## scrape configs are going to break Prometheus after the upgrade.
+ ## AdditionalScrapeConfigs can be defined as a list or as a templated string.
+ ##
+ ## The scrape configuration example below will find master nodes, provided they have the name .*mst.*, relabel the
+ ## port to 2379 and allow etcd scraping provided it is running on all Kubernetes master nodes
+ ##
+ additionalScrapeConfigs: []
+ # - job_name: kube-etcd
+ # kubernetes_sd_configs:
+ # - role: node
+ # scheme: https
+ # tls_config:
+ # ca_file: /etc/prometheus/secrets/etcd-client-cert/etcd-ca
+ # cert_file: /etc/prometheus/secrets/etcd-client-cert/etcd-client
+ # key_file: /etc/prometheus/secrets/etcd-client-cert/etcd-client-key
+ # relabel_configs:
+ # - action: labelmap
+ # regex: __meta_kubernetes_node_label_(.+)
+ # - source_labels: [__address__]
+ # action: replace
+ # targetLabel: __address__
+ # regex: ([^:;]+):(\d+)
+ # replacement: ${1}:2379
+ # - source_labels: [__meta_kubernetes_node_name]
+ # action: keep
+ # regex: .*mst.*
+ # - source_labels: [__meta_kubernetes_node_name]
+ # action: replace
+ # targetLabel: node
+ # regex: (.*)
+ # replacement: ${1}
+ # metric_relabel_configs:
+ # - regex: (kubernetes_io_hostname|failure_domain_beta_kubernetes_io_region|beta_kubernetes_io_os|beta_kubernetes_io_arch|beta_kubernetes_io_instance_type|failure_domain_beta_kubernetes_io_zone)
+ # action: labeldrop
+ #
+ ## If scrape config contains a repetitive section, you may want to use a template.
+ ## In the following example, you can see how to define `gce_sd_configs` for multiple zones
+ # additionalScrapeConfigs: |
+ # - job_name: "node-exporter"
+ # gce_sd_configs:
+ # {{range $zone := .Values.gcp_zones}}
+ # - project: "project1"
+ # zone: "{{$zone}}"
+ # port: 9100
+ # {{end}}
+ # relabel_configs:
+ # ...
+
+
+ ## If additional scrape configurations are already deployed in a single secret file you can use this section.
+ ## Expected values are the secret name and key
+ ## Cannot be used with additionalScrapeConfigs
+ additionalScrapeConfigsSecret: {}
+ # enabled: false
+ # name:
+ # key:
+
+ ## additionalPrometheusSecretsAnnotations allows to add annotations to the kubernetes secret. This can be useful
+ ## when deploying via spinnaker to disable versioning on the secret, strategy.spinnaker.io/versioned: 'false'
+ additionalPrometheusSecretsAnnotations: {}
+
+ ## AdditionalAlertManagerConfigs allows for manual configuration of alertmanager jobs in the form as specified
+ ## in the official Prometheus documentation https://prometheus.io/docs/prometheus/latest/configuration/configuration/#.
+ ## AlertManager configurations specified are appended to the configurations generated by the Prometheus Operator.
+ ## As AlertManager configs are appended, the user is responsible to make sure it is valid. Note that using this
+ ## feature may expose the possibility to break upgrades of Prometheus. It is advised to review Prometheus release
+ ## notes to ensure that no incompatible AlertManager configs are going to break Prometheus after the upgrade.
+ ##
+ additionalAlertManagerConfigs: []
+ # - consul_sd_configs:
+ # - server: consul.dev.test:8500
+ # scheme: http
+ # datacenter: dev
+ # tag_separator: ','
+ # services:
+ # - metrics-prometheus-alertmanager
+
+ ## If additional alertmanager configurations are already deployed in a single secret, or you want to manage
+ ## them separately from the helm deployment, you can use this section.
+ ## Expected values are the secret name and key
+ ## Cannot be used with additionalAlertManagerConfigs
+ additionalAlertManagerConfigsSecret: {}
+ # name:
+ # key:
+ # optional: false
+
+ ## AdditionalAlertRelabelConfigs allows specifying Prometheus alert relabel configurations. Alert relabel configurations specified are appended
+ ## to the configurations generated by the Prometheus Operator. Alert relabel configurations specified must have the form as specified in the
+ ## official Prometheus documentation: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#alert_relabel_configs.
+ ## As alert relabel configs are appended, the user is responsible to make sure it is valid. Note that using this feature may expose the
+ ## possibility to break upgrades of Prometheus. It is advised to review Prometheus release notes to ensure that no incompatible alert relabel
+ ## configs are going to break Prometheus after the upgrade.
+ ##
+ additionalAlertRelabelConfigs: []
+ # - separator: ;
+ # regex: prometheus_replica
+ # replacement: $1
+ # action: labeldrop
+
+ ## If additional alert relabel configurations are already deployed in a single secret, or you want to manage
+ ## them separately from the helm deployment, you can use this section.
+ ## Expected values are the secret name and key
+ ## Cannot be used with additionalAlertRelabelConfigs
+ additionalAlertRelabelConfigsSecret: {}
+ # name:
+ # key:
+
+ ## SecurityContext holds pod-level security attributes and common container settings.
+ ## This defaults to non root user with uid 1000 and gid 2000.
+ ## https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md
+ ##
+ securityContext:
+ runAsGroup: 2000
+ runAsNonRoot: true
+ runAsUser: 1000
+ fsGroup: 2000
+
+ ## Priority class assigned to the Pods
+ ##
+ priorityClassName: ""
+
+ ## Thanos configuration allows configuring various aspects of a Prometheus server in a Thanos environment.
+ ## This section is experimental, it may change significantly without deprecation notice in any release.
+ ## This is experimental and may change significantly without backward compatibility in any release.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#thanosspec
+ ##
+ thanos: {}
+ # secretProviderClass:
+ # provider: gcp
+ # parameters:
+ # secrets: |
+ # - resourceName: "projects/$PROJECT_ID/secrets/testsecret/versions/latest"
+ # fileName: "objstore.yaml"
+ # objectStorageConfigFile: /var/secrets/object-store.yaml
+
+ ## Containers allows injecting additional containers. This is meant to allow adding an authentication proxy to a Prometheus pod.
+ ## if using proxy extraContainer update targetPort with proxy container port
+ containers: []
+ # containers:
+ # - name: oauth-proxy
+ # image: quay.io/oauth2-proxy/oauth2-proxy:v7.3.0
+ # args:
+ # - --upstream=http://127.0.0.1:9093
+ # - --http-address=0.0.0.0:8081
+ # - ...
+ # ports:
+ # - containerPort: 8081
+ # name: oauth-proxy
+ # protocol: TCP
+ # resources: {}
+
+ ## InitContainers allows injecting additional initContainers. This is meant to allow doing some changes
+ ## (permissions, dir tree) on mounted volumes before starting prometheus
+ initContainers: []
+
+ ## PortName to use for Prometheus.
+ ##
+ portName: "http-web"
+
+ ## ArbitraryFSAccessThroughSMs configures whether configuration based on a service monitor can access arbitrary files
+ ## on the file system of the Prometheus container e.g. bearer token files.
+ arbitraryFSAccessThroughSMs: false
+
+ ## OverrideHonorLabels if set to true overrides all user configured honor_labels. If HonorLabels is set in ServiceMonitor
+ ## or PodMonitor to true, this overrides honor_labels to false.
+ overrideHonorLabels: false
+
+ ## OverrideHonorTimestamps allows to globally enforce honoring timestamps in all scrape configs.
+ overrideHonorTimestamps: false
+
+ ## IgnoreNamespaceSelectors if set to true will ignore NamespaceSelector settings from the podmonitor and servicemonitor
+ ## configs, and they will only discover endpoints within their current namespace. Defaults to false.
+ ignoreNamespaceSelectors: false
+
+ ## EnforcedNamespaceLabel enforces adding a namespace label of origin for each alert and metric that is user created.
+ ## The label value will always be the namespace of the object that is being created.
+ ## Disabled by default
+ enforcedNamespaceLabel: ""
+
+ ## PrometheusRulesExcludedFromEnforce - list of prometheus rules to be excluded from enforcing of adding namespace labels.
+ ## Works only if enforcedNamespaceLabel set to true. Make sure both ruleNamespace and ruleName are set for each pair
+ ## Deprecated, use `excludedFromEnforcement` instead
+ prometheusRulesExcludedFromEnforce: []
+
+ ## ExcludedFromEnforcement - list of object references to PodMonitor, ServiceMonitor, Probe and PrometheusRule objects
+ ## to be excluded from enforcing a namespace label of origin.
+ ## Works only if enforcedNamespaceLabel set to true.
+ ## See https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#objectreference
+ excludedFromEnforcement: []
+
+ ## QueryLogFile specifies the file to which PromQL queries are logged. Note that this location must be writable,
+ ## and can be persisted using an attached volume. Alternatively, the location can be set to a stdout location such
+ ## as /dev/stdout to log querie information to the default Prometheus log stream. This is only available in versions
+ ## of Prometheus >= 2.16.0. For more details, see the Prometheus docs (https://prometheus.io/docs/guides/query-log/)
+ queryLogFile: false
+
+ ## EnforcedSampleLimit defines global limit on number of scraped samples that will be accepted. This overrides any SampleLimit
+ ## set per ServiceMonitor or/and PodMonitor. It is meant to be used by admins to enforce the SampleLimit to keep overall
+ ## number of samples/series under the desired limit. Note that if SampleLimit is lower that value will be taken instead.
+ enforcedSampleLimit: false
+
+ ## EnforcedTargetLimit defines a global limit on the number of scraped targets. This overrides any TargetLimit set
+ ## per ServiceMonitor or/and PodMonitor. It is meant to be used by admins to enforce the TargetLimit to keep the overall
+ ## number of targets under the desired limit. Note that if TargetLimit is lower, that value will be taken instead, except
+ ## if either value is zero, in which case the non-zero value will be used. If both values are zero, no limit is enforced.
+ enforcedTargetLimit: false
+
+
+ ## Per-scrape limit on number of labels that will be accepted for a sample. If more than this number of labels are present
+ ## post metric-relabeling, the entire scrape will be treated as failed. 0 means no limit. Only valid in Prometheus versions
+ ## 2.27.0 and newer.
+ enforcedLabelLimit: false
+
+ ## Per-scrape limit on length of labels name that will be accepted for a sample. If a label name is longer than this number
+ ## post metric-relabeling, the entire scrape will be treated as failed. 0 means no limit. Only valid in Prometheus versions
+ ## 2.27.0 and newer.
+ enforcedLabelNameLengthLimit: false
+
+ ## Per-scrape limit on length of labels value that will be accepted for a sample. If a label value is longer than this
+ ## number post metric-relabeling, the entire scrape will be treated as failed. 0 means no limit. Only valid in Prometheus
+ ## versions 2.27.0 and newer.
+ enforcedLabelValueLengthLimit: false
+
+ ## AllowOverlappingBlocks enables vertical compaction and vertical query merge in Prometheus. This is still experimental
+ ## in Prometheus so it may change in any upcoming release.
+ allowOverlappingBlocks: false
+
+ ## Minimum number of seconds for which a newly created pod should be ready without any of its container crashing for it to
+ ## be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).
+ minReadySeconds: 0
+
+ additionalRulesForClusterRole: []
+ # - apiGroups: [ "" ]
+ # resources:
+ # - nodes/proxy
+ # verbs: [ "get", "list", "watch" ]
+
+ additionalServiceMonitors: []
+ ## Name of the ServiceMonitor to create
+ ##
+ # - name: ""
+
+ ## Additional labels to set used for the ServiceMonitorSelector. Together with standard labels from
+ ## the chart
+ ##
+ # additionalLabels: {}
+
+ ## Service label for use in assembling a job name of the form -
+ ## If no label is specified, the service name is used.
+ ##
+ # jobLabel: ""
+
+ ## labels to transfer from the kubernetes service to the target
+ ##
+ # targetLabels: []
+
+ ## labels to transfer from the kubernetes pods to the target
+ ##
+ # podTargetLabels: []
+
+ ## Label selector for services to which this ServiceMonitor applies
+ ##
+ # selector: {}
+
+ ## Namespaces from which services are selected
+ ##
+ # namespaceSelector:
+ ## Match any namespace
+ ##
+ # any: false
+
+ ## Explicit list of namespace names to select
+ ##
+ # matchNames: []
+
+ ## Endpoints of the selected service to be monitored
+ ##
+ # endpoints: []
+ ## Name of the endpoint's service port
+ ## Mutually exclusive with targetPort
+ # - port: ""
+
+ ## Name or number of the endpoint's target port
+ ## Mutually exclusive with port
+ # - targetPort: ""
+
+ ## File containing bearer token to be used when scraping targets
+ ##
+ # bearerTokenFile: ""
+
+ ## Interval at which metrics should be scraped
+ ##
+ # interval: 30s
+
+ ## HTTP path to scrape for metrics
+ ##
+ # path: /metrics
+
+ ## HTTP scheme to use for scraping
+ ##
+ # scheme: http
+
+ ## TLS configuration to use when scraping the endpoint
+ ##
+ # tlsConfig:
+
+ ## Path to the CA file
+ ##
+ # caFile: ""
+
+ ## Path to client certificate file
+ ##
+ # certFile: ""
+
+ ## Skip certificate verification
+ ##
+ # insecureSkipVerify: false
+
+ ## Path to client key file
+ ##
+ # keyFile: ""
+
+ ## Server name used to verify host name
+ ##
+ # serverName: ""
+
+ additionalPodMonitors: []
+ ## Name of the PodMonitor to create
+ ##
+ # - name: ""
+
+ ## Additional labels to set used for the PodMonitorSelector. Together with standard labels from
+ ## the chart
+ ##
+ # additionalLabels: {}
+
+ ## Pod label for use in assembling a job name of the form -
+ ## If no label is specified, the pod endpoint name is used.
+ ##
+ # jobLabel: ""
+
+ ## Label selector for pods to which this PodMonitor applies
+ ##
+ # selector: {}
+
+ ## PodTargetLabels transfers labels on the Kubernetes Pod onto the target.
+ ##
+ # podTargetLabels: {}
+
+ ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted.
+ ##
+ # sampleLimit: 0
+
+ ## Namespaces from which pods are selected
+ ##
+ # namespaceSelector:
+ ## Match any namespace
+ ##
+ # any: false
+
+ ## Explicit list of namespace names to select
+ ##
+ # matchNames: []
+
+ ## Endpoints of the selected pods to be monitored
+ ## https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#podmetricsendpoint
+ ##
+ # podMetricsEndpoints: []
+
+## Configuration for thanosRuler
+## ref: https://thanos.io/tip/components/rule.md/
+##
+thanosRuler:
+
+ ## Deploy thanosRuler
+ ##
+ enabled: false
+
+ ## Annotations for ThanosRuler
+ ##
+ annotations: {}
+
+ ## Service account for ThanosRuler to use.
+ ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
+ ##
+ serviceAccount:
+ create: true
+ name: ""
+ annotations: {}
+
+ ## Configure pod disruption budgets for ThanosRuler
+ ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget
+ ## This configuration is immutable once created and will require the PDB to be deleted to be changed
+ ## https://github.com/kubernetes/kubernetes/issues/45398
+ ##
+ podDisruptionBudget:
+ enabled: false
+ minAvailable: 1
+ maxUnavailable: ""
+
+ ingress:
+ enabled: false
+
+ # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
+ # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
+ # ingressClassName: nginx
+
+ annotations: {}
+
+ labels: {}
+
+ ## Hosts must be provided if Ingress is enabled.
+ ##
+ hosts: []
+ # - thanosruler.domain.com
+
+ ## Paths to use for ingress rules - one path should match the thanosruler.routePrefix
+ ##
+ paths: []
+ # - /
+
+ ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched)
+ ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types
+ # pathType: ImplementationSpecific
+
+ ## TLS configuration for ThanosRuler Ingress
+ ## Secret must be manually created in the namespace
+ ##
+ tls: []
+ # - secretName: thanosruler-general-tls
+ # hosts:
+ # - thanosruler.example.com
+
+ ## Configuration for ThanosRuler service
+ ##
+ service:
+ annotations: {}
+ labels: {}
+ clusterIP: ""
+
+ ## Port for ThanosRuler Service to listen on
+ ##
+ port: 10902
+ ## To be used with a proxy extraContainer port
+ ##
+ targetPort: 10902
+ ## Port to expose on each node
+ ## Only used if service.type is 'NodePort'
+ ##
+ nodePort: 30905
+ ## List of IP addresses at which the Prometheus server service is available
+ ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips
+ ##
+
+ ## Additional ports to open for ThanosRuler service
+ additionalPorts: []
+
+ externalIPs: []
+ loadBalancerIP: ""
+ loadBalancerSourceRanges: []
+
+ ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints
+ ##
+ externalTrafficPolicy: Cluster
+
+ ## Service type
+ ##
+ type: ClusterIP
+
+ ## If true, create a serviceMonitor for thanosRuler
+ ##
+ serviceMonitor:
+ ## Scrape interval. If not set, the Prometheus default scrape interval is used.
+ ##
+ interval: ""
+ selfMonitor: true
+
+ ## proxyUrl: URL of a proxy that should be used for scraping.
+ ##
+ proxyUrl: ""
+
+ ## scheme: HTTP scheme to use for scraping. Can be used with `tlsConfig` for example if using istio mTLS.
+ scheme: ""
+
+ ## tlsConfig: TLS configuration to use when scraping the endpoint. For example if using istio mTLS.
+ ## Of type: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#tlsconfig
+ tlsConfig: {}
+
+ bearerTokenFile:
+
+ ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ metricRelabelings: []
+ # - action: keep
+ # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
+ # sourceLabels: [__name__]
+
+ ## RelabelConfigs to apply to samples before scraping
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig
+ ##
+ relabelings: []
+ # - sourceLabels: [__meta_kubernetes_pod_node_name]
+ # separator: ;
+ # regex: ^(.*)$
+ # targetLabel: nodename
+ # replacement: $1
+ # action: replace
+
+ ## Settings affecting thanosRulerpec
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#thanosrulerspec
+ ##
+ thanosRulerSpec:
+ ## Standard object's metadata. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata
+ ## Metadata Labels and Annotations gets propagated to the ThanosRuler pods.
+ ##
+ podMetadata: {}
+
+ ## Image of ThanosRuler
+ ##
+ image:
+ repository: quay.io/thanos/thanos
+ tag: v0.28.0
+ sha: ""
+
+ ## Namespaces to be selected for PrometheusRules discovery.
+ ## If nil, select own namespace. Namespaces to be selected for ServiceMonitor discovery.
+ ## See https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#namespaceselector for usage
+ ##
+ ruleNamespaceSelector: {}
+
+ ## If true, a nil or {} value for thanosRuler.thanosRulerSpec.ruleSelector will cause the
+ ## prometheus resource to be created with selectors based on values in the helm deployment,
+ ## which will also match the PrometheusRule resources created
+ ##
+ ruleSelectorNilUsesHelmValues: true
+
+ ## PrometheusRules to be selected for target discovery.
+ ## If {}, select all PrometheusRules
+ ##
+ ruleSelector: {}
+ ## Example which select all PrometheusRules resources
+ ## with label "prometheus" with values any of "example-rules" or "example-rules-2"
+ # ruleSelector:
+ # matchExpressions:
+ # - key: prometheus
+ # operator: In
+ # values:
+ # - example-rules
+ # - example-rules-2
+ #
+ ## Example which select all PrometheusRules resources with label "role" set to "example-rules"
+ # ruleSelector:
+ # matchLabels:
+ # role: example-rules
+
+ ## Define Log Format
+ # Use logfmt (default) or json logging
+ logFormat: logfmt
+
+ ## Log level for ThanosRuler to be configured with.
+ ##
+ logLevel: info
+
+ ## Size is the expected size of the thanosRuler cluster. The controller will eventually make the size of the
+ ## running cluster equal to the expected size.
+ replicas: 1
+
+ ## Time duration ThanosRuler shall retain data for. Default is '24h', and must match the regular expression
+ ## [0-9]+(ms|s|m|h) (milliseconds seconds minutes hours).
+ ##
+ retention: 24h
+
+ ## Interval between consecutive evaluations.
+ ##
+ evaluationInterval: ""
+
+ ## Storage is the definition of how storage will be used by the ThanosRuler instances.
+ ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/storage.md
+ ##
+ storage: {}
+ # volumeClaimTemplate:
+ # spec:
+ # storageClassName: gluster
+ # accessModes: ["ReadWriteOnce"]
+ # resources:
+ # requests:
+ # storage: 50Gi
+ # selector: {}
+
+ ## AlertmanagerConfig define configuration for connecting to alertmanager.
+ ## Only available with Thanos v0.10.0 and higher. Maps to the alertmanagers.config Thanos Ruler arg.
+ alertmanagersConfig: {}
+ # - api_version: v2
+ # http_config:
+ # basic_auth:
+ # username: some_user
+ # password: some_pass
+ # static_configs:
+ # - alertmanager.thanos.io
+ # scheme: http
+ # timeout: 10s
+
+ ## DEPRECATED. Define URLs to send alerts to Alertmanager. For Thanos v0.10.0 and higher, alertmanagersConfig should be used instead.
+ ## Note: this field will be ignored if alertmanagersConfig is specified. Maps to the alertmanagers.url Thanos Ruler arg.
+ # alertmanagersUrl:
+
+ ## The external URL the Thanos Ruler instances will be available under. This is necessary to generate correct URLs. This is necessary if Thanos Ruler is not served from root of a DNS name. string false
+ ##
+ externalPrefix:
+
+ ## The route prefix ThanosRuler registers HTTP handlers for. This is useful, if using ExternalURL and a proxy is rewriting HTTP routes of a request, and the actual ExternalURL is still true,
+ ## but the server serves requests under a different route prefix. For example for use with kubectl proxy.
+ ##
+ routePrefix: /
+
+ ## ObjectStorageConfig configures object storage in Thanos. Alternative to
+ ## ObjectStorageConfigFile, and lower order priority.
+ objectStorageConfig: {}
+
+ ## ObjectStorageConfigFile specifies the path of the object storage configuration file.
+ ## When used alongside with ObjectStorageConfig, ObjectStorageConfigFile takes precedence.
+ objectStorageConfigFile: ""
+
+ ## Labels configure the external label pairs to ThanosRuler. A default replica
+ ## label `thanos_ruler_replica` will be always added as a label with the value
+ ## of the pod's name and it will be dropped in the alerts.
+ labels: {}
+
+ ## If set to true all actions on the underlying managed objects are not going to be performed, except for delete actions.
+ ##
+ paused: false
+
+ ## Define which Nodes the Pods are scheduled on.
+ ## ref: https://kubernetes.io/docs/user-guide/node-selection/
+ ##
+ nodeSelector: {}
+
+ ## Define resources requests and limits for single Pods.
+ ## ref: https://kubernetes.io/docs/user-guide/compute-resources/
+ ##
+ resources: {}
+ # requests:
+ # memory: 400Mi
+
+ ## Pod anti-affinity can prevent the scheduler from placing Prometheus replicas on the same node.
+ ## The default value "soft" means that the scheduler should *prefer* to not schedule two replica pods onto the same node but no guarantee is provided.
+ ## The value "hard" means that the scheduler is *required* to not schedule two replica pods onto the same node.
+ ## The value "" will disable pod anti-affinity so that no anti-affinity rules will be configured.
+ ##
+ podAntiAffinity: ""
+
+ ## If anti-affinity is enabled sets the topologyKey to use for anti-affinity.
+ ## This can be changed to, for example, failure-domain.beta.kubernetes.io/zone
+ ##
+ podAntiAffinityTopologyKey: kubernetes.io/hostname
+
+ ## Assign custom affinity rules to the thanosRuler instance
+ ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
+ ##
+ affinity: {}
+ # nodeAffinity:
+ # requiredDuringSchedulingIgnoredDuringExecution:
+ # nodeSelectorTerms:
+ # - matchExpressions:
+ # - key: kubernetes.io/e2e-az-name
+ # operator: In
+ # values:
+ # - e2e-az1
+ # - e2e-az2
+
+ ## If specified, the pod's tolerations.
+ ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+ ##
+ tolerations: []
+ # - key: "key"
+ # operator: "Equal"
+ # value: "value"
+ # effect: "NoSchedule"
+
+ ## If specified, the pod's topology spread constraints.
+ ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
+ ##
+ topologySpreadConstraints: []
+ # - maxSkew: 1
+ # topologyKey: topology.kubernetes.io/zone
+ # whenUnsatisfiable: DoNotSchedule
+ # labelSelector:
+ # matchLabels:
+ # app: thanos-ruler
+
+ ## SecurityContext holds pod-level security attributes and common container settings.
+ ## This defaults to non root user with uid 1000 and gid 2000. *v1.PodSecurityContext false
+ ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
+ ##
+ securityContext:
+ runAsGroup: 2000
+ runAsNonRoot: true
+ runAsUser: 1000
+ fsGroup: 2000
+
+ ## ListenLocal makes the ThanosRuler server listen on loopback, so that it does not bind against the Pod IP.
+ ## Note this is only for the ThanosRuler UI, not the gossip communication.
+ ##
+ listenLocal: false
+
+ ## Containers allows injecting additional containers. This is meant to allow adding an authentication proxy to an ThanosRuler pod.
+ ##
+ containers: []
+
+ # Additional volumes on the output StatefulSet definition.
+ volumes: []
+
+ # Additional VolumeMounts on the output StatefulSet definition.
+ volumeMounts: []
+
+ ## InitContainers allows injecting additional initContainers. This is meant to allow doing some changes
+ ## (permissions, dir tree) on mounted volumes before starting prometheus
+ initContainers: []
+
+ ## Priority class assigned to the Pods
+ ##
+ priorityClassName: ""
+
+ ## PortName to use for ThanosRuler.
+ ##
+ portName: "web"
+
+ ## ExtraSecret can be used to store various data in an extra secret
+ ## (use it for example to store hashed basic auth credentials)
+ extraSecret:
+ ## if not set, name will be auto generated
+ # name: ""
+ annotations: {}
+ data: {}
+ # auth: |
+ # foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0
+ # someoneelse:$apr1$DMZX2Z4q$6SbQIfyuLQd.xmo/P0m2c.
+
+## Setting to true produces cleaner resource names, but requires a data migration because the name of the persistent volume changes. Therefore this should only be set once on initial installation.
+##
+cleanPrometheusOperatorObjectNames: false
diff --git a/kube-prometheus-stack/get_helm.sh b/kube-prometheus-stack/get_helm.sh
new file mode 100644
index 00000000..9c603586
--- /dev/null
+++ b/kube-prometheus-stack/get_helm.sh
@@ -0,0 +1,326 @@
+#!/usr/bin/env bash
+
+# Copyright The Helm Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The install script is based off of the MIT-licensed script from glide,
+# the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get
+
+: ${BINARY_NAME:="helm"}
+: ${USE_SUDO:="true"}
+: ${DEBUG:="false"}
+: ${VERIFY_CHECKSUM:="true"}
+: ${VERIFY_SIGNATURES:="false"}
+: ${HELM_INSTALL_DIR:="/usr/local/bin"}
+: ${GPG_PUBRING:="pubring.kbx"}
+
+HAS_CURL="$(type "curl" &> /dev/null && echo true || echo false)"
+HAS_WGET="$(type "wget" &> /dev/null && echo true || echo false)"
+HAS_OPENSSL="$(type "openssl" &> /dev/null && echo true || echo false)"
+HAS_GPG="$(type "gpg" &> /dev/null && echo true || echo false)"
+
+# initArch discovers the architecture for this system.
+initArch() {
+ ARCH=$(uname -m)
+ case $ARCH in
+ armv5*) ARCH="armv5";;
+ armv6*) ARCH="armv6";;
+ armv7*) ARCH="arm";;
+ aarch64) ARCH="arm64";;
+ x86) ARCH="386";;
+ x86_64) ARCH="amd64";;
+ i686) ARCH="386";;
+ i386) ARCH="386";;
+ esac
+}
+
+# initOS discovers the operating system for this system.
+initOS() {
+ OS=$(echo `uname`|tr '[:upper:]' '[:lower:]')
+
+ case "$OS" in
+ # Minimalist GNU for Windows
+ mingw*|cygwin*) OS='windows';;
+ esac
+}
+
+# runs the given command as root (detects if we are root already)
+runAsRoot() {
+ if [ $EUID -ne 0 -a "$USE_SUDO" = "true" ]; then
+ sudo "${@}"
+ else
+ "${@}"
+ fi
+}
+
+# verifySupported checks that the os/arch combination is supported for
+# binary builds, as well whether or not necessary tools are present.
+verifySupported() {
+ local supported="darwin-amd64\ndarwin-arm64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nlinux-s390x\nwindows-amd64"
+ if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then
+ echo "No prebuilt binary for ${OS}-${ARCH}."
+ echo "To build from source, go to https://github.com/helm/helm"
+ exit 1
+ fi
+
+ if [ "${HAS_CURL}" != "true" ] && [ "${HAS_WGET}" != "true" ]; then
+ echo "Either curl or wget is required"
+ exit 1
+ fi
+
+ if [ "${VERIFY_CHECKSUM}" == "true" ] && [ "${HAS_OPENSSL}" != "true" ]; then
+ echo "In order to verify checksum, openssl must first be installed."
+ echo "Please install openssl or set VERIFY_CHECKSUM=false in your environment."
+ exit 1
+ fi
+
+ if [ "${VERIFY_SIGNATURES}" == "true" ]; then
+ if [ "${HAS_GPG}" != "true" ]; then
+ echo "In order to verify signatures, gpg must first be installed."
+ echo "Please install gpg or set VERIFY_SIGNATURES=false in your environment."
+ exit 1
+ fi
+ if [ "${OS}" != "linux" ]; then
+ echo "Signature verification is currently only supported on Linux."
+ echo "Please set VERIFY_SIGNATURES=false or verify the signatures manually."
+ exit 1
+ fi
+ fi
+}
+
+# checkDesiredVersion checks if the desired version is available.
+checkDesiredVersion() {
+ if [ "x$DESIRED_VERSION" == "x" ]; then
+ # Get tag from release URL
+ local latest_release_url="https://github.com/helm/helm/releases"
+ if [ "${HAS_CURL}" == "true" ]; then
+ TAG=$(curl -Ls $latest_release_url | grep 'href="/helm/helm/releases/tag/v3.[0-9]*.[0-9]*\"' | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]+)".*/\1/g' | head -1)
+ elif [ "${HAS_WGET}" == "true" ]; then
+ TAG=$(wget $latest_release_url -O - 2>&1 | grep 'href="/helm/helm/releases/tag/v3.[0-9]*.[0-9]*\"' | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]+)".*/\1/g' | head -1)
+ fi
+ else
+ TAG=$DESIRED_VERSION
+ fi
+}
+
+# checkHelmInstalledVersion checks which version of helm is installed and
+# if it needs to be changed.
+checkHelmInstalledVersion() {
+ if [[ -f "${HELM_INSTALL_DIR}/${BINARY_NAME}" ]]; then
+ local version=$("${HELM_INSTALL_DIR}/${BINARY_NAME}" version --template="{{ .Version }}")
+ if [[ "$version" == "$TAG" ]]; then
+ echo "Helm ${version} is already ${DESIRED_VERSION:-latest}"
+ return 0
+ else
+ echo "Helm ${TAG} is available. Changing from version ${version}."
+ return 1
+ fi
+ else
+ return 1
+ fi
+}
+
+# downloadFile downloads the latest binary package and also the checksum
+# for that binary.
+downloadFile() {
+ HELM_DIST="helm-$TAG-$OS-$ARCH.tar.gz"
+ DOWNLOAD_URL="https://get.helm.sh/$HELM_DIST"
+ CHECKSUM_URL="$DOWNLOAD_URL.sha256"
+ HELM_TMP_ROOT="$(mktemp -dt helm-installer-XXXXXX)"
+ HELM_TMP_FILE="$HELM_TMP_ROOT/$HELM_DIST"
+ HELM_SUM_FILE="$HELM_TMP_ROOT/$HELM_DIST.sha256"
+ echo "Downloading $DOWNLOAD_URL"
+ if [ "${HAS_CURL}" == "true" ]; then
+ curl -SsL "$CHECKSUM_URL" -o "$HELM_SUM_FILE"
+ curl -SsL "$DOWNLOAD_URL" -o "$HELM_TMP_FILE"
+ elif [ "${HAS_WGET}" == "true" ]; then
+ wget -q -O "$HELM_SUM_FILE" "$CHECKSUM_URL"
+ wget -q -O "$HELM_TMP_FILE" "$DOWNLOAD_URL"
+ fi
+}
+
+# verifyFile verifies the SHA256 checksum of the binary package
+# and the GPG signatures for both the package and checksum file
+# (depending on settings in environment).
+verifyFile() {
+ if [ "${VERIFY_CHECKSUM}" == "true" ]; then
+ verifyChecksum
+ fi
+ if [ "${VERIFY_SIGNATURES}" == "true" ]; then
+ verifySignatures
+ fi
+}
+
+# installFile installs the Helm binary.
+installFile() {
+ HELM_TMP="$HELM_TMP_ROOT/$BINARY_NAME"
+ mkdir -p "$HELM_TMP"
+ tar xf "$HELM_TMP_FILE" -C "$HELM_TMP"
+ HELM_TMP_BIN="$HELM_TMP/$OS-$ARCH/helm"
+ echo "Preparing to install $BINARY_NAME into ${HELM_INSTALL_DIR}"
+ runAsRoot cp "$HELM_TMP_BIN" "$HELM_INSTALL_DIR/$BINARY_NAME"
+ echo "$BINARY_NAME installed into $HELM_INSTALL_DIR/$BINARY_NAME"
+}
+
+# verifyChecksum verifies the SHA256 checksum of the binary package.
+verifyChecksum() {
+ printf "Verifying checksum... "
+ local sum=$(openssl sha1 -sha256 ${HELM_TMP_FILE} | awk '{print $2}')
+ local expected_sum=$(cat ${HELM_SUM_FILE})
+ if [ "$sum" != "$expected_sum" ]; then
+ echo "SHA sum of ${HELM_TMP_FILE} does not match. Aborting."
+ exit 1
+ fi
+ echo "Done."
+}
+
+# verifySignatures obtains the latest KEYS file from GitHub main branch
+# as well as the signature .asc files from the specific GitHub release,
+# then verifies that the release artifacts were signed by a maintainer's key.
+verifySignatures() {
+ printf "Verifying signatures... "
+ local keys_filename="KEYS"
+ local github_keys_url="https://raw.githubusercontent.com/helm/helm/main/${keys_filename}"
+ if [ "${HAS_CURL}" == "true" ]; then
+ curl -SsL "${github_keys_url}" -o "${HELM_TMP_ROOT}/${keys_filename}"
+ elif [ "${HAS_WGET}" == "true" ]; then
+ wget -q -O "${HELM_TMP_ROOT}/${keys_filename}" "${github_keys_url}"
+ fi
+ local gpg_keyring="${HELM_TMP_ROOT}/keyring.gpg"
+ local gpg_homedir="${HELM_TMP_ROOT}/gnupg"
+ mkdir -p -m 0700 "${gpg_homedir}"
+ local gpg_stderr_device="/dev/null"
+ if [ "${DEBUG}" == "true" ]; then
+ gpg_stderr_device="/dev/stderr"
+ fi
+ gpg --batch --quiet --homedir="${gpg_homedir}" --import "${HELM_TMP_ROOT}/${keys_filename}" 2> "${gpg_stderr_device}"
+ gpg --batch --no-default-keyring --keyring "${gpg_homedir}/${GPG_PUBRING}" --export > "${gpg_keyring}"
+ local github_release_url="https://github.com/helm/helm/releases/download/${TAG}"
+ if [ "${HAS_CURL}" == "true" ]; then
+ curl -SsL "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" -o "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc"
+ curl -SsL "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" -o "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc"
+ elif [ "${HAS_WGET}" == "true" ]; then
+ wget -q -O "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc"
+ wget -q -O "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc"
+ fi
+ local error_text="If you think this might be a potential security issue,"
+ error_text="${error_text}\nplease see here: https://github.com/helm/community/blob/master/SECURITY.md"
+ local num_goodlines_sha=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)')
+ if [[ ${num_goodlines_sha} -lt 2 ]]; then
+ echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256!"
+ echo -e "${error_text}"
+ exit 1
+ fi
+ local num_goodlines_tar=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)')
+ if [[ ${num_goodlines_tar} -lt 2 ]]; then
+ echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz!"
+ echo -e "${error_text}"
+ exit 1
+ fi
+ echo "Done."
+}
+
+# fail_trap is executed if an error occurs.
+fail_trap() {
+ result=$?
+ if [ "$result" != "0" ]; then
+ if [[ -n "$INPUT_ARGUMENTS" ]]; then
+ echo "Failed to install $BINARY_NAME with the arguments provided: $INPUT_ARGUMENTS"
+ help
+ else
+ echo "Failed to install $BINARY_NAME"
+ fi
+ echo -e "\tFor support, go to https://github.com/helm/helm."
+ fi
+ cleanup
+ exit $result
+}
+
+# testVersion tests the installed client to make sure it is working.
+testVersion() {
+ set +e
+ HELM="$(command -v $BINARY_NAME)"
+ if [ "$?" = "1" ]; then
+ echo "$BINARY_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?'
+ exit 1
+ fi
+ set -e
+}
+
+# help provides possible cli installation arguments
+help () {
+ echo "Accepted cli arguments are:"
+ echo -e "\t[--help|-h ] ->> prints this help"
+ echo -e "\t[--version|-v ] . When not defined it fetches the latest release from GitHub"
+ echo -e "\te.g. --version v3.0.0 or -v canary"
+ echo -e "\t[--no-sudo] ->> install without sudo"
+}
+
+# cleanup temporary files to avoid https://github.com/helm/helm/issues/2977
+cleanup() {
+ if [[ -d "${HELM_TMP_ROOT:-}" ]]; then
+ rm -rf "$HELM_TMP_ROOT"
+ fi
+}
+
+# Execution
+
+#Stop execution on any error
+trap "fail_trap" EXIT
+set -e
+
+# Set debug if desired
+if [ "${DEBUG}" == "true" ]; then
+ set -x
+fi
+
+# Parsing input arguments (if any)
+export INPUT_ARGUMENTS="${@}"
+set -u
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ '--version'|-v)
+ shift
+ if [[ $# -ne 0 ]]; then
+ export DESIRED_VERSION="${1}"
+ else
+ echo -e "Please provide the desired version. e.g. --version v3.0.0 or -v canary"
+ exit 0
+ fi
+ ;;
+ '--no-sudo')
+ USE_SUDO="false"
+ ;;
+ '--help'|-h)
+ help
+ exit 0
+ ;;
+ *) exit 1
+ ;;
+ esac
+ shift
+done
+set +u
+
+initArch
+initOS
+verifySupported
+checkDesiredVersion
+if ! checkHelmInstalledVersion; then
+ downloadFile
+ verifyFile
+ installFile
+fi
+testVersion
+cleanup
diff --git a/kube-prometheus-stack/templates/NOTES.txt b/kube-prometheus-stack/templates/NOTES.txt
new file mode 100644
index 00000000..371f3ae3
--- /dev/null
+++ b/kube-prometheus-stack/templates/NOTES.txt
@@ -0,0 +1,4 @@
+{{ $.Chart.Name }} has been installed. Check its status by running:
+ kubectl --namespace {{ template "kube-prometheus-stack.namespace" . }} get pods -l "release={{ $.Release.Name }}"
+
+Visit https://github.com/prometheus-operator/kube-prometheus for instructions on how to create & configure Alertmanager and Prometheus instances using the Operator.
diff --git a/kube-prometheus-stack/templates/_helpers.tpl b/kube-prometheus-stack/templates/_helpers.tpl
new file mode 100644
index 00000000..25eb226a
--- /dev/null
+++ b/kube-prometheus-stack/templates/_helpers.tpl
@@ -0,0 +1,249 @@
+{{/* vim: set filetype=mustache: */}}
+{{/* Expand the name of the chart. This is suffixed with -alertmanager, which means subtract 13 from longest 63 available */}}
+{{- define "kube-prometheus-stack.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 50 | 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.
+The components in this chart create additional resources that expand the longest created name strings.
+The longest name that gets created adds and extra 37 characters, so truncation should be 63-35=26.
+*/}}
+{{- define "kube-prometheus-stack.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 26 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 26 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 26 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/* Fullname suffixed with operator */}}
+{{- define "kube-prometheus-stack.operator.fullname" -}}
+{{- printf "%s-operator" (include "kube-prometheus-stack.fullname" .) -}}
+{{- end }}
+
+{{/* Prometheus custom resource instance name */}}
+{{- define "kube-prometheus-stack.prometheus.crname" -}}
+{{- if .Values.cleanPrometheusOperatorObjectNames }}
+{{- include "kube-prometheus-stack.fullname" . }}
+{{- else }}
+{{- print (include "kube-prometheus-stack.fullname" .) "-prometheus" }}
+{{- end }}
+{{- end }}
+
+{{/* Alertmanager custom resource instance name */}}
+{{- define "kube-prometheus-stack.alertmanager.crname" -}}
+{{- if .Values.cleanPrometheusOperatorObjectNames }}
+{{- include "kube-prometheus-stack.fullname" . }}
+{{- else }}
+{{- print (include "kube-prometheus-stack.fullname" .) "-alertmanager" -}}
+{{- end }}
+{{- end }}
+
+{{/* Fullname suffixed with thanos-ruler */}}
+{{- define "kube-prometheus-stack.thanosRuler.fullname" -}}
+{{- printf "%s-thanos-ruler" (include "kube-prometheus-stack.fullname" .) -}}
+{{- end }}
+
+{{/* Create chart name and version as used by the chart label. */}}
+{{- define "kube-prometheus-stack.chartref" -}}
+{{- replace "+" "_" .Chart.Version | printf "%s-%s" .Chart.Name -}}
+{{- end }}
+
+{{/* Generate basic labels */}}
+{{- define "kube-prometheus-stack.labels" }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+app.kubernetes.io/version: "{{ replace "+" "_" .Chart.Version }}"
+app.kubernetes.io/part-of: {{ template "kube-prometheus-stack.name" . }}
+chart: {{ template "kube-prometheus-stack.chartref" . }}
+release: {{ $.Release.Name | quote }}
+heritage: {{ $.Release.Service | quote }}
+{{- if .Values.commonLabels}}
+{{ toYaml .Values.commonLabels }}
+{{- end }}
+{{- end }}
+
+{{/* Create the name of kube-prometheus-stack service account to use */}}
+{{- define "kube-prometheus-stack.operator.serviceAccountName" -}}
+{{- if .Values.prometheusOperator.serviceAccount.create -}}
+ {{ default (include "kube-prometheus-stack.operator.fullname" .) .Values.prometheusOperator.serviceAccount.name }}
+{{- else -}}
+ {{ default "default" .Values.prometheusOperator.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
+
+{{/* Create the name of prometheus service account to use */}}
+{{- define "kube-prometheus-stack.prometheus.serviceAccountName" -}}
+{{- if .Values.prometheus.serviceAccount.create -}}
+ {{ default (print (include "kube-prometheus-stack.fullname" .) "-prometheus") .Values.prometheus.serviceAccount.name }}
+{{- else -}}
+ {{ default "default" .Values.prometheus.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
+
+{{/* Create the name of alertmanager service account to use */}}
+{{- define "kube-prometheus-stack.alertmanager.serviceAccountName" -}}
+{{- if .Values.alertmanager.serviceAccount.create -}}
+ {{ default (print (include "kube-prometheus-stack.fullname" .) "-alertmanager") .Values.alertmanager.serviceAccount.name }}
+{{- else -}}
+ {{ default "default" .Values.alertmanager.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
+
+{{/* Create the name of thanosRuler service account to use */}}
+{{- define "kube-prometheus-stack.thanosRuler.serviceAccountName" -}}
+{{- if .Values.thanosRuler.serviceAccount.create -}}
+ {{ default (include "kube-prometheus-stack.thanosRuler.fullname" .) .Values.thanosRuler.serviceAccount.name }}
+{{- else -}}
+ {{ default "default" .Values.thanosRuler.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Allow the release namespace to be overridden for multi-namespace deployments in combined charts
+*/}}
+{{- define "kube-prometheus-stack.namespace" -}}
+ {{- if .Values.namespaceOverride -}}
+ {{- .Values.namespaceOverride -}}
+ {{- else -}}
+ {{- .Release.Namespace -}}
+ {{- end -}}
+{{- end -}}
+
+{{/*
+Use the grafana namespace override for multi-namespace deployments in combined charts
+*/}}
+{{- define "kube-prometheus-stack-grafana.namespace" -}}
+ {{- if .Values.grafana.namespaceOverride -}}
+ {{- .Values.grafana.namespaceOverride -}}
+ {{- else -}}
+ {{- .Release.Namespace -}}
+ {{- end -}}
+{{- end -}}
+
+{{/*
+Use the kube-state-metrics namespace override for multi-namespace deployments in combined charts
+*/}}
+{{- define "kube-prometheus-stack-kube-state-metrics.namespace" -}}
+ {{- if index .Values "kube-state-metrics" "namespaceOverride" -}}
+ {{- index .Values "kube-state-metrics" "namespaceOverride" -}}
+ {{- else -}}
+ {{- .Release.Namespace -}}
+ {{- end -}}
+{{- end -}}
+
+{{/*
+Use the prometheus-node-exporter namespace override for multi-namespace deployments in combined charts
+*/}}
+{{- define "kube-prometheus-stack-prometheus-node-exporter.namespace" -}}
+ {{- if index .Values "prometheus-node-exporter" "namespaceOverride" -}}
+ {{- index .Values "prometheus-node-exporter" "namespaceOverride" -}}
+ {{- else -}}
+ {{- .Release.Namespace -}}
+ {{- end -}}
+{{- end -}}
+
+{{/* Allow KubeVersion to be overridden. */}}
+{{- define "kube-prometheus-stack.kubeVersion" -}}
+ {{- default .Capabilities.KubeVersion.Version .Values.kubeVersionOverride -}}
+{{- end -}}
+
+{{/* Get Ingress API Version */}}
+{{- define "kube-prometheus-stack.ingress.apiVersion" -}}
+ {{- if and (.Capabilities.APIVersions.Has "networking.k8s.io/v1") (semverCompare ">= 1.19-0" (include "kube-prometheus-stack.kubeVersion" .)) -}}
+ {{- print "networking.k8s.io/v1" -}}
+ {{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
+ {{- print "networking.k8s.io/v1beta1" -}}
+ {{- else -}}
+ {{- print "extensions/v1beta1" -}}
+ {{- end -}}
+{{- end -}}
+
+{{/* Check Ingress stability */}}
+{{- define "kube-prometheus-stack.ingress.isStable" -}}
+ {{- eq (include "kube-prometheus-stack.ingress.apiVersion" .) "networking.k8s.io/v1" -}}
+{{- end -}}
+
+{{/* Check Ingress supports pathType */}}
+{{/* pathType was added to networking.k8s.io/v1beta1 in Kubernetes 1.18 */}}
+{{- define "kube-prometheus-stack.ingress.supportsPathType" -}}
+ {{- or (eq (include "kube-prometheus-stack.ingress.isStable" .) "true") (and (eq (include "kube-prometheus-stack.ingress.apiVersion" .) "networking.k8s.io/v1beta1") (semverCompare ">= 1.18-0" (include "kube-prometheus-stack.kubeVersion" .))) -}}
+{{- end -}}
+
+{{/* Get Policy API Version */}}
+{{- define "kube-prometheus-stack.pdb.apiVersion" -}}
+ {{- if and (.Capabilities.APIVersions.Has "policy/v1") (semverCompare ">= 1.21-0" (include "kube-prometheus-stack.kubeVersion" .)) -}}
+ {{- print "policy/v1" -}}
+ {{- else -}}
+ {{- print "policy/v1beta1" -}}
+ {{- end -}}
+ {{- end -}}
+
+{{/* Get value based on current Kubernetes version */}}
+{{- define "kube-prometheus-stack.kubeVersionDefaultValue" -}}
+ {{- $values := index . 0 -}}
+ {{- $kubeVersion := index . 1 -}}
+ {{- $old := index . 2 -}}
+ {{- $new := index . 3 -}}
+ {{- $default := index . 4 -}}
+ {{- if kindIs "invalid" $default -}}
+ {{- if semverCompare $kubeVersion (include "kube-prometheus-stack.kubeVersion" $values) -}}
+ {{- print $new -}}
+ {{- else -}}
+ {{- print $old -}}
+ {{- end -}}
+ {{- else -}}
+ {{- print $default }}
+ {{- end -}}
+{{- end -}}
+
+{{/* Get value for kube-controller-manager depending on insecure scraping availability */}}
+{{- define "kube-prometheus-stack.kubeControllerManager.insecureScrape" -}}
+ {{- $values := index . 0 -}}
+ {{- $insecure := index . 1 -}}
+ {{- $secure := index . 2 -}}
+ {{- $userValue := index . 3 -}}
+ {{- include "kube-prometheus-stack.kubeVersionDefaultValue" (list $values ">= 1.22-0" $insecure $secure $userValue) -}}
+{{- end -}}
+
+{{/* Get value for kube-scheduler depending on insecure scraping availability */}}
+{{- define "kube-prometheus-stack.kubeScheduler.insecureScrape" -}}
+ {{- $values := index . 0 -}}
+ {{- $insecure := index . 1 -}}
+ {{- $secure := index . 2 -}}
+ {{- $userValue := index . 3 -}}
+ {{- include "kube-prometheus-stack.kubeVersionDefaultValue" (list $values ">= 1.23-0" $insecure $secure $userValue) -}}
+{{- end -}}
+
+{{/*
+To help compatibility with other charts which use global.imagePullSecrets.
+Allow either an array of {name: pullSecret} maps (k8s-style), or an array of strings (more common helm-style).
+global:
+ imagePullSecrets:
+ - name: pullSecret1
+ - name: pullSecret2
+
+or
+
+global:
+ imagePullSecrets:
+ - pullSecret1
+ - pullSecret2
+*/}}
+{{- define "kube-prometheus-stack.imagePullSecrets" -}}
+{{- range .Values.global.imagePullSecrets }}
+ {{- if eq (typeOf .) "map[string]interface {}" }}
+- {{ toYaml . | trim }}
+ {{- else }}
+- name: {{ . }}
+ {{- end }}
+{{- end }}
+{{- end -}}
diff --git a/kube-prometheus-stack/templates/alertmanager/alertmanager.yaml b/kube-prometheus-stack/templates/alertmanager/alertmanager.yaml
new file mode 100644
index 00000000..a1e4749d
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/alertmanager.yaml
@@ -0,0 +1,168 @@
+{{- if .Values.alertmanager.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: Alertmanager
+metadata:
+ name: {{ template "kube-prometheus-stack.alertmanager.crname" . }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.alertmanager.annotations }}
+ annotations:
+{{ toYaml .Values.alertmanager.annotations | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.alertmanager.alertmanagerSpec.image }}
+ {{- if and .Values.alertmanager.alertmanagerSpec.image.tag .Values.alertmanager.alertmanagerSpec.image.sha }}
+ image: "{{ .Values.alertmanager.alertmanagerSpec.image.repository }}:{{ .Values.alertmanager.alertmanagerSpec.image.tag }}@sha256:{{ .Values.alertmanager.alertmanagerSpec.image.sha }}"
+ {{- else if .Values.alertmanager.alertmanagerSpec.image.sha }}
+ image: "{{ .Values.alertmanager.alertmanagerSpec.image.repository }}@sha256:{{ .Values.alertmanager.alertmanagerSpec.image.sha }}"
+ {{- else if .Values.alertmanager.alertmanagerSpec.image.tag }}
+ image: "{{ .Values.alertmanager.alertmanagerSpec.image.repository }}:{{ .Values.alertmanager.alertmanagerSpec.image.tag }}"
+ {{- else }}
+ image: "{{ .Values.alertmanager.alertmanagerSpec.image.repository }}"
+ {{- end }}
+ version: {{ .Values.alertmanager.alertmanagerSpec.image.tag }}
+ {{- if .Values.alertmanager.alertmanagerSpec.image.sha }}
+ sha: {{ .Values.alertmanager.alertmanagerSpec.image.sha }}
+ {{- end }}
+{{- end }}
+ replicas: {{ .Values.alertmanager.alertmanagerSpec.replicas }}
+ listenLocal: {{ .Values.alertmanager.alertmanagerSpec.listenLocal }}
+ serviceAccountName: {{ template "kube-prometheus-stack.alertmanager.serviceAccountName" . }}
+{{- if .Values.alertmanager.alertmanagerSpec.externalUrl }}
+ externalUrl: "{{ tpl .Values.alertmanager.alertmanagerSpec.externalUrl . }}"
+{{- else if and .Values.alertmanager.ingress.enabled .Values.alertmanager.ingress.hosts }}
+ externalUrl: "http://{{ tpl (index .Values.alertmanager.ingress.hosts 0) . }}{{ .Values.alertmanager.alertmanagerSpec.routePrefix }}"
+{{- else }}
+ externalUrl: http://{{ template "kube-prometheus-stack.fullname" . }}-alertmanager.{{ template "kube-prometheus-stack.namespace" . }}:{{ .Values.alertmanager.service.port }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.nodeSelector }}
+ nodeSelector:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.nodeSelector | indent 4 }}
+{{- end }}
+ paused: {{ .Values.alertmanager.alertmanagerSpec.paused }}
+ logFormat: {{ .Values.alertmanager.alertmanagerSpec.logFormat | quote }}
+ logLevel: {{ .Values.alertmanager.alertmanagerSpec.logLevel | quote }}
+ retention: {{ .Values.alertmanager.alertmanagerSpec.retention | quote }}
+{{- if .Values.alertmanager.alertmanagerSpec.secrets }}
+ secrets:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.secrets | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.configSecret }}
+ configSecret: {{ .Values.alertmanager.alertmanagerSpec.configSecret }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.configMaps }}
+ configMaps:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.configMaps | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.alertmanagerConfigSelector }}
+ alertmanagerConfigSelector:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.alertmanagerConfigSelector | indent 4}}
+{{ else }}
+ alertmanagerConfigSelector: {}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.alertmanagerConfigNamespaceSelector }}
+ alertmanagerConfigNamespaceSelector:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.alertmanagerConfigNamespaceSelector | indent 4}}
+{{ else }}
+ alertmanagerConfigNamespaceSelector: {}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.web }}
+ web:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.web | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.alertmanagerConfiguration }}
+ alertmanagerConfiguration:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.alertmanagerConfiguration | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.resources }}
+ resources:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.resources | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.routePrefix }}
+ routePrefix: "{{ .Values.alertmanager.alertmanagerSpec.routePrefix }}"
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.securityContext }}
+ securityContext:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.securityContext | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.storage }}
+ storage:
+{{ tpl (toYaml .Values.alertmanager.alertmanagerSpec.storage | indent 4) . }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.podMetadata }}
+ podMetadata:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.podMetadata | indent 4 }}
+{{- end }}
+{{- if or .Values.alertmanager.alertmanagerSpec.podAntiAffinity .Values.alertmanager.alertmanagerSpec.affinity }}
+ affinity:
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.affinity }}
+{{ toYaml .Values.alertmanager.alertmanagerSpec.affinity | indent 4 }}
+{{- end }}
+{{- if eq .Values.alertmanager.alertmanagerSpec.podAntiAffinity "hard" }}
+ podAntiAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ - topologyKey: {{ .Values.alertmanager.alertmanagerSpec.podAntiAffinityTopologyKey }}
+ labelSelector:
+ matchExpressions:
+ - {key: app.kubernetes.io/name, operator: In, values: [alertmanager]}
+ - {key: alertmanager, operator: In, values: [{{ template "kube-prometheus-stack.alertmanager.crname" . }}]}
+{{- else if eq .Values.alertmanager.alertmanagerSpec.podAntiAffinity "soft" }}
+ podAntiAffinity:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ - weight: 100
+ podAffinityTerm:
+ topologyKey: {{ .Values.alertmanager.alertmanagerSpec.podAntiAffinityTopologyKey }}
+ labelSelector:
+ matchExpressions:
+ - {key: app.kubernetes.io/name, operator: In, values: [alertmanager]}
+ - {key: alertmanager, operator: In, values: [{{ template "kube-prometheus-stack.alertmanager.crname" . }}]}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.tolerations }}
+ tolerations:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.tolerations | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.topologySpreadConstraints }}
+ topologySpreadConstraints:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.topologySpreadConstraints | indent 4 }}
+{{- end }}
+{{- if .Values.global.imagePullSecrets }}
+ imagePullSecrets:
+{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.containers }}
+ containers:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.containers | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.initContainers }}
+ initContainers:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.initContainers | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.priorityClassName }}
+ priorityClassName: {{.Values.alertmanager.alertmanagerSpec.priorityClassName }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.additionalPeers }}
+ additionalPeers:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.additionalPeers | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.volumes }}
+ volumes:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.volumes | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.volumeMounts }}
+ volumeMounts:
+{{ toYaml .Values.alertmanager.alertmanagerSpec.volumeMounts | indent 4 }}
+{{- end }}
+ portName: {{ .Values.alertmanager.alertmanagerSpec.portName }}
+{{- if .Values.alertmanager.alertmanagerSpec.clusterAdvertiseAddress }}
+ clusterAdvertiseAddress: {{ .Values.alertmanager.alertmanagerSpec.clusterAdvertiseAddress }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.forceEnableClusterMode }}
+ forceEnableClusterMode: {{ .Values.alertmanager.alertmanagerSpec.forceEnableClusterMode }}
+{{- end }}
+{{- if .Values.alertmanager.alertmanagerSpec.minReadySeconds }}
+ minReadySeconds: {{ .Values.alertmanager.alertmanagerSpec.minReadySeconds }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/alertmanager/extrasecret.yaml b/kube-prometheus-stack/templates/alertmanager/extrasecret.yaml
new file mode 100644
index 00000000..ecd8f470
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/extrasecret.yaml
@@ -0,0 +1,20 @@
+{{- if .Values.alertmanager.extraSecret.data -}}
+{{- $secretName := printf "alertmanager-%s-extra" (include "kube-prometheus-stack.fullname" . ) -}}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ default $secretName .Values.alertmanager.extraSecret.name }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- if .Values.alertmanager.extraSecret.annotations }}
+ annotations:
+{{ toYaml .Values.alertmanager.extraSecret.annotations | indent 4 }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+ app.kubernetes.io/component: alertmanager
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+data:
+{{- range $key, $val := .Values.alertmanager.extraSecret.data }}
+ {{ $key }}: {{ $val | b64enc | quote }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/alertmanager/ingress.yaml b/kube-prometheus-stack/templates/alertmanager/ingress.yaml
new file mode 100644
index 00000000..29c9cbce
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/ingress.yaml
@@ -0,0 +1,77 @@
+{{- if and .Values.alertmanager.enabled .Values.alertmanager.ingress.enabled }}
+{{- $pathType := .Values.alertmanager.ingress.pathType | default "ImplementationSpecific" }}
+{{- $serviceName := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "alertmanager" }}
+{{- $servicePort := .Values.alertmanager.ingress.servicePort | default .Values.alertmanager.service.port -}}
+{{- $routePrefix := list .Values.alertmanager.alertmanagerSpec.routePrefix }}
+{{- $paths := .Values.alertmanager.ingress.paths | default $routePrefix -}}
+{{- $apiIsStable := eq (include "kube-prometheus-stack.ingress.isStable" .) "true" -}}
+{{- $ingressSupportsPathType := eq (include "kube-prometheus-stack.ingress.supportsPathType" .) "true" -}}
+apiVersion: {{ include "kube-prometheus-stack.ingress.apiVersion" . }}
+kind: Ingress
+metadata:
+ name: {{ $serviceName }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- if .Values.alertmanager.ingress.annotations }}
+ annotations:
+{{ toYaml .Values.alertmanager.ingress.annotations | indent 4 }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+{{- if .Values.alertmanager.ingress.labels }}
+{{ toYaml .Values.alertmanager.ingress.labels | indent 4 }}
+{{- end }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ {{- if $apiIsStable }}
+ {{- if .Values.alertmanager.ingress.ingressClassName }}
+ ingressClassName: {{ .Values.alertmanager.ingress.ingressClassName }}
+ {{- end }}
+ {{- end }}
+ rules:
+ {{- if .Values.alertmanager.ingress.hosts }}
+ {{- range $host := .Values.alertmanager.ingress.hosts }}
+ - host: {{ tpl $host $ }}
+ http:
+ paths:
+ {{- range $p := $paths }}
+ - path: {{ tpl $p $ }}
+ {{- if and $pathType $ingressSupportsPathType }}
+ pathType: {{ $pathType }}
+ {{- end }}
+ backend:
+ {{- if $apiIsStable }}
+ service:
+ name: {{ $serviceName }}
+ port:
+ number: {{ $servicePort }}
+ {{- else }}
+ serviceName: {{ $serviceName }}
+ servicePort: {{ $servicePort }}
+ {{- end }}
+ {{- end -}}
+ {{- end -}}
+ {{- else }}
+ - http:
+ paths:
+ {{- range $p := $paths }}
+ - path: {{ tpl $p $ }}
+ {{- if and $pathType $ingressSupportsPathType }}
+ pathType: {{ $pathType }}
+ {{- end }}
+ backend:
+ {{- if $apiIsStable }}
+ service:
+ name: {{ $serviceName }}
+ port:
+ number: {{ $servicePort }}
+ {{- else }}
+ serviceName: {{ $serviceName }}
+ servicePort: {{ $servicePort }}
+ {{- end }}
+ {{- end -}}
+ {{- end -}}
+ {{- if .Values.alertmanager.ingress.tls }}
+ tls:
+{{ tpl (toYaml .Values.alertmanager.ingress.tls | indent 4) . }}
+ {{- end -}}
+{{- end -}}
diff --git a/kube-prometheus-stack/templates/alertmanager/ingressperreplica.yaml b/kube-prometheus-stack/templates/alertmanager/ingressperreplica.yaml
new file mode 100644
index 00000000..f21bf961
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/ingressperreplica.yaml
@@ -0,0 +1,67 @@
+{{- if and .Values.alertmanager.enabled .Values.alertmanager.servicePerReplica.enabled .Values.alertmanager.ingressPerReplica.enabled }}
+{{- $pathType := .Values.alertmanager.ingressPerReplica.pathType | default "" }}
+{{- $count := .Values.alertmanager.alertmanagerSpec.replicas | int -}}
+{{- $servicePort := .Values.alertmanager.service.port -}}
+{{- $ingressValues := .Values.alertmanager.ingressPerReplica -}}
+{{- $apiIsStable := eq (include "kube-prometheus-stack.ingress.isStable" .) "true" -}}
+{{- $ingressSupportsPathType := eq (include "kube-prometheus-stack.ingress.supportsPathType" .) "true" -}}
+apiVersion: v1
+kind: List
+metadata:
+ name: {{ include "kube-prometheus-stack.fullname" $ }}-alertmanager-ingressperreplica
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+items:
+{{ range $i, $e := until $count }}
+ - kind: Ingress
+ apiVersion: {{ include "kube-prometheus-stack.ingress.apiVersion" $ }}
+ metadata:
+ name: {{ include "kube-prometheus-stack.fullname" $ }}-alertmanager-{{ $i }}
+ namespace: {{ template "kube-prometheus-stack.namespace" $ }}
+ labels:
+ app: {{ include "kube-prometheus-stack.name" $ }}-alertmanager
+ {{ include "kube-prometheus-stack.labels" $ | indent 8 }}
+ {{- if $ingressValues.labels }}
+{{ toYaml $ingressValues.labels | indent 8 }}
+ {{- end }}
+ {{- if $ingressValues.annotations }}
+ annotations:
+{{ toYaml $ingressValues.annotations | indent 8 }}
+ {{- end }}
+ spec:
+ {{- if $apiIsStable }}
+ {{- if $ingressValues.ingressClassName }}
+ ingressClassName: {{ $ingressValues.ingressClassName }}
+ {{- end }}
+ {{- end }}
+ rules:
+ - host: {{ $ingressValues.hostPrefix }}-{{ $i }}.{{ $ingressValues.hostDomain }}
+ http:
+ paths:
+ {{- range $p := $ingressValues.paths }}
+ - path: {{ tpl $p $ }}
+ {{- if and $pathType $ingressSupportsPathType }}
+ pathType: {{ $pathType }}
+ {{- end }}
+ backend:
+ {{- if $apiIsStable }}
+ service:
+ name: {{ include "kube-prometheus-stack.fullname" $ }}-alertmanager-{{ $i }}
+ port:
+ number: {{ $servicePort }}
+ {{- else }}
+ serviceName: {{ include "kube-prometheus-stack.fullname" $ }}-alertmanager-{{ $i }}
+ servicePort: {{ $servicePort }}
+ {{- end }}
+ {{- end -}}
+ {{- if or $ingressValues.tlsSecretName $ingressValues.tlsSecretPerReplica.enabled }}
+ tls:
+ - hosts:
+ - {{ $ingressValues.hostPrefix }}-{{ $i }}.{{ $ingressValues.hostDomain }}
+ {{- if $ingressValues.tlsSecretPerReplica.enabled }}
+ secretName: {{ $ingressValues.tlsSecretPerReplica.prefix }}-{{ $i }}
+ {{- else }}
+ secretName: {{ $ingressValues.tlsSecretName }}
+ {{- end }}
+ {{- end }}
+{{- end -}}
+{{- end -}}
diff --git a/kube-prometheus-stack/templates/alertmanager/podDisruptionBudget.yaml b/kube-prometheus-stack/templates/alertmanager/podDisruptionBudget.yaml
new file mode 100644
index 00000000..b1834031
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/podDisruptionBudget.yaml
@@ -0,0 +1,21 @@
+{{- if and .Values.alertmanager.enabled .Values.alertmanager.podDisruptionBudget.enabled }}
+apiVersion: {{ include "kube-prometheus-stack.pdb.apiVersion" . }}
+kind: PodDisruptionBudget
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ {{- if .Values.alertmanager.podDisruptionBudget.minAvailable }}
+ minAvailable: {{ .Values.alertmanager.podDisruptionBudget.minAvailable }}
+ {{- end }}
+ {{- if .Values.alertmanager.podDisruptionBudget.maxUnavailable }}
+ maxUnavailable: {{ .Values.alertmanager.podDisruptionBudget.maxUnavailable }}
+ {{- end }}
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: alertmanager
+ alertmanager: {{ template "kube-prometheus-stack.alertmanager.crname" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/alertmanager/psp-role.yaml b/kube-prometheus-stack/templates/alertmanager/psp-role.yaml
new file mode 100644
index 00000000..d64d1f81
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/psp-role.yaml
@@ -0,0 +1,21 @@
+{{- if and .Values.alertmanager.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }}
+kind: Role
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+rules:
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if semverCompare "> 1.15.0-0" $kubeTargetVersion }}
+- apiGroups: ['policy']
+{{- else }}
+- apiGroups: ['extensions']
+{{- end }}
+ resources: ['podsecuritypolicies']
+ verbs: ['use']
+ resourceNames:
+ - {{ template "kube-prometheus-stack.fullname" . }}-alertmanager
+{{- end }}
diff --git a/kube-prometheus-stack/templates/alertmanager/psp-rolebinding.yaml b/kube-prometheus-stack/templates/alertmanager/psp-rolebinding.yaml
new file mode 100644
index 00000000..9248cc8d
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/psp-rolebinding.yaml
@@ -0,0 +1,18 @@
+{{- if and .Values.alertmanager.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager
+subjects:
+ - kind: ServiceAccount
+ name: {{ template "kube-prometheus-stack.alertmanager.serviceAccountName" . }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/alertmanager/psp.yaml b/kube-prometheus-stack/templates/alertmanager/psp.yaml
new file mode 100644
index 00000000..b60fbbd5
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/psp.yaml
@@ -0,0 +1,46 @@
+{{- if and .Values.alertmanager.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }}
+apiVersion: policy/v1beta1
+kind: PodSecurityPolicy
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+{{- if .Values.global.rbac.pspAnnotations }}
+ annotations:
+{{ toYaml .Values.global.rbac.pspAnnotations | indent 4 }}
+{{- end }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ privileged: false
+ # Allow core volume types.
+ volumes:
+ - 'configMap'
+ - 'emptyDir'
+ - 'projected'
+ - 'secret'
+ - 'downwardAPI'
+ - 'persistentVolumeClaim'
+ hostNetwork: false
+ hostIPC: false
+ hostPID: false
+ runAsUser:
+ # Permits the container to run with root privileges as well.
+ rule: 'RunAsAny'
+ seLinux:
+ # This policy assumes the nodes are using AppArmor rather than SELinux.
+ rule: 'RunAsAny'
+ supplementalGroups:
+ rule: 'MustRunAs'
+ ranges:
+ # Allow adding the root group.
+ - min: 0
+ max: 65535
+ fsGroup:
+ rule: 'MustRunAs'
+ ranges:
+ # Allow adding the root group.
+ - min: 0
+ max: 65535
+ readOnlyRootFilesystem: false
+{{- end }}
+
diff --git a/kube-prometheus-stack/templates/alertmanager/secret.yaml b/kube-prometheus-stack/templates/alertmanager/secret.yaml
new file mode 100644
index 00000000..0a354a3b
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/secret.yaml
@@ -0,0 +1,27 @@
+{{- if and (.Values.alertmanager.enabled) (not .Values.alertmanager.alertmanagerSpec.useExistingSecret) }}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: alertmanager-{{ template "kube-prometheus-stack.alertmanager.crname" . }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- if .Values.alertmanager.secret.annotations }}
+ annotations:
+{{ toYaml .Values.alertmanager.secret.annotations | indent 4 }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+data:
+{{- if .Values.alertmanager.tplConfig }}
+{{- if eq (typeOf .Values.alertmanager.config) "string" }}
+ alertmanager.yaml: {{ tpl (.Values.alertmanager.config) . | b64enc | quote }}
+{{- else }}
+ alertmanager.yaml: {{ tpl (toYaml .Values.alertmanager.config) . | b64enc | quote }}
+{{- end }}
+{{- else }}
+ alertmanager.yaml: {{ toYaml .Values.alertmanager.config | b64enc | quote }}
+{{- end}}
+{{- range $key, $val := .Values.alertmanager.templateFiles }}
+ {{ $key }}: {{ $val | b64enc | quote }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/alertmanager/service.yaml b/kube-prometheus-stack/templates/alertmanager/service.yaml
new file mode 100644
index 00000000..44100ec1
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/service.yaml
@@ -0,0 +1,53 @@
+{{- if .Values.alertmanager.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+ self-monitor: {{ .Values.alertmanager.serviceMonitor.selfMonitor | quote }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.alertmanager.service.labels }}
+{{ toYaml .Values.alertmanager.service.labels | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.service.annotations }}
+ annotations:
+{{ toYaml .Values.alertmanager.service.annotations | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.alertmanager.service.clusterIP }}
+ clusterIP: {{ .Values.alertmanager.service.clusterIP }}
+{{- end }}
+{{- if .Values.alertmanager.service.externalIPs }}
+ externalIPs:
+{{ toYaml .Values.alertmanager.service.externalIPs | indent 4 }}
+{{- end }}
+{{- if .Values.alertmanager.service.loadBalancerIP }}
+ loadBalancerIP: {{ .Values.alertmanager.service.loadBalancerIP }}
+{{- end }}
+{{- if .Values.alertmanager.service.loadBalancerSourceRanges }}
+ loadBalancerSourceRanges:
+ {{- range $cidr := .Values.alertmanager.service.loadBalancerSourceRanges }}
+ - {{ $cidr }}
+ {{- end }}
+{{- end }}
+{{- if ne .Values.alertmanager.service.type "ClusterIP" }}
+ externalTrafficPolicy: {{ .Values.alertmanager.service.externalTrafficPolicy }}
+{{- end }}
+ ports:
+ - name: {{ .Values.alertmanager.alertmanagerSpec.portName }}
+ {{- if eq .Values.alertmanager.service.type "NodePort" }}
+ nodePort: {{ .Values.alertmanager.service.nodePort }}
+ {{- end }}
+ port: {{ .Values.alertmanager.service.port }}
+ targetPort: {{ .Values.alertmanager.service.targetPort }}
+ protocol: TCP
+{{- if .Values.alertmanager.service.additionalPorts }}
+{{ toYaml .Values.alertmanager.service.additionalPorts | indent 2 }}
+{{- end }}
+ selector:
+ app.kubernetes.io/name: alertmanager
+ alertmanager: {{ template "kube-prometheus-stack.alertmanager.crname" . }}
+ type: "{{ .Values.alertmanager.service.type }}"
+{{- end }}
diff --git a/kube-prometheus-stack/templates/alertmanager/serviceaccount.yaml b/kube-prometheus-stack/templates/alertmanager/serviceaccount.yaml
new file mode 100644
index 00000000..ae433d55
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/serviceaccount.yaml
@@ -0,0 +1,20 @@
+{{- if and .Values.alertmanager.enabled .Values.alertmanager.serviceAccount.create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ template "kube-prometheus-stack.alertmanager.serviceAccountName" . }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+ app.kubernetes.io/name: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+ app.kubernetes.io/component: alertmanager
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.alertmanager.serviceAccount.annotations }}
+ annotations:
+{{ toYaml .Values.alertmanager.serviceAccount.annotations | indent 4 }}
+{{- end }}
+{{- if .Values.global.imagePullSecrets }}
+imagePullSecrets:
+{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 2}}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/alertmanager/servicemonitor.yaml b/kube-prometheus-stack/templates/alertmanager/servicemonitor.yaml
new file mode 100644
index 00000000..2dc9b868
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/servicemonitor.yaml
@@ -0,0 +1,45 @@
+{{- if and .Values.alertmanager.enabled .Values.alertmanager.serviceMonitor.selfMonitor }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ selector:
+ matchLabels:
+ app: {{ template "kube-prometheus-stack.name" . }}-alertmanager
+ release: {{ $.Release.Name | quote }}
+ self-monitor: "true"
+ namespaceSelector:
+ matchNames:
+ - {{ printf "%s" (include "kube-prometheus-stack.namespace" .) | quote }}
+ endpoints:
+ - port: {{ .Values.alertmanager.alertmanagerSpec.portName }}
+ {{- if .Values.alertmanager.serviceMonitor.interval }}
+ interval: {{ .Values.alertmanager.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.alertmanager.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.alertmanager.serviceMonitor.proxyUrl}}
+ {{- end }}
+ {{- if .Values.alertmanager.serviceMonitor.scheme }}
+ scheme: {{ .Values.alertmanager.serviceMonitor.scheme }}
+ {{- end }}
+ {{- if .Values.alertmanager.serviceMonitor.bearerTokenFile }}
+ bearerTokenFile: {{ .Values.alertmanager.serviceMonitor.bearerTokenFile }}
+ {{- end }}
+ {{- if .Values.alertmanager.serviceMonitor.tlsConfig }}
+ tlsConfig: {{ toYaml .Values.alertmanager.serviceMonitor.tlsConfig | nindent 6 }}
+ {{- end }}
+ path: "{{ trimSuffix "/" .Values.alertmanager.alertmanagerSpec.routePrefix }}/metrics"
+{{- if .Values.alertmanager.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.alertmanager.serviceMonitor.metricRelabelings | indent 6) . }}
+{{- end }}
+{{- if .Values.alertmanager.serviceMonitor.relabelings }}
+ relabelings:
+{{ toYaml .Values.alertmanager.serviceMonitor.relabelings | indent 6 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/alertmanager/serviceperreplica.yaml b/kube-prometheus-stack/templates/alertmanager/serviceperreplica.yaml
new file mode 100644
index 00000000..75a13bdf
--- /dev/null
+++ b/kube-prometheus-stack/templates/alertmanager/serviceperreplica.yaml
@@ -0,0 +1,49 @@
+{{- if and .Values.alertmanager.enabled .Values.alertmanager.servicePerReplica.enabled }}
+{{- $count := .Values.alertmanager.alertmanagerSpec.replicas | int -}}
+{{- $serviceValues := .Values.alertmanager.servicePerReplica -}}
+apiVersion: v1
+kind: List
+metadata:
+ name: {{ include "kube-prometheus-stack.fullname" $ }}-alertmanager-serviceperreplica
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+items:
+{{- range $i, $e := until $count }}
+ - apiVersion: v1
+ kind: Service
+ metadata:
+ name: {{ include "kube-prometheus-stack.fullname" $ }}-alertmanager-{{ $i }}
+ namespace: {{ template "kube-prometheus-stack.namespace" $ }}
+ labels:
+ app: {{ include "kube-prometheus-stack.name" $ }}-alertmanager
+{{ include "kube-prometheus-stack.labels" $ | indent 8 }}
+ {{- if $serviceValues.annotations }}
+ annotations:
+{{ toYaml $serviceValues.annotations | indent 8 }}
+ {{- end }}
+ spec:
+ {{- if $serviceValues.clusterIP }}
+ clusterIP: {{ $serviceValues.clusterIP }}
+ {{- end }}
+ {{- if $serviceValues.loadBalancerSourceRanges }}
+ loadBalancerSourceRanges:
+ {{- range $cidr := $serviceValues.loadBalancerSourceRanges }}
+ - {{ $cidr }}
+ {{- end }}
+ {{- end }}
+ {{- if ne $serviceValues.type "ClusterIP" }}
+ externalTrafficPolicy: {{ $serviceValues.externalTrafficPolicy }}
+ {{- end }}
+ ports:
+ - name: {{ $.Values.alertmanager.alertmanagerSpec.portName }}
+ {{- if eq $serviceValues.type "NodePort" }}
+ nodePort: {{ $serviceValues.nodePort }}
+ {{- end }}
+ port: {{ $serviceValues.port }}
+ targetPort: {{ $serviceValues.targetPort }}
+ selector:
+ app.kubernetes.io/name: alertmanager
+ alertmanager: {{ template "kube-prometheus-stack.alertmanager.crname" $ }}
+ statefulset.kubernetes.io/pod-name: alertmanager-{{ include "kube-prometheus-stack.alertmanager.crname" $ }}-{{ $i }}
+ type: "{{ $serviceValues.type }}"
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/core-dns/service.yaml b/kube-prometheus-stack/templates/exporters/core-dns/service.yaml
new file mode 100644
index 00000000..f77db419
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/core-dns/service.yaml
@@ -0,0 +1,24 @@
+{{- if .Values.coreDns.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-coredns
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-coredns
+ jobLabel: coredns
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+ namespace: kube-system
+spec:
+ clusterIP: None
+ ports:
+ - name: http-metrics
+ port: {{ .Values.coreDns.service.port }}
+ protocol: TCP
+ targetPort: {{ .Values.coreDns.service.targetPort }}
+ selector:
+ {{- if .Values.coreDns.service.selector }}
+{{ toYaml .Values.coreDns.service.selector | indent 4 }}
+ {{- else}}
+ k8s-app: kube-dns
+ {{- end}}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/core-dns/servicemonitor.yaml b/kube-prometheus-stack/templates/exporters/core-dns/servicemonitor.yaml
new file mode 100644
index 00000000..8d501374
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/core-dns/servicemonitor.yaml
@@ -0,0 +1,39 @@
+{{- if .Values.coreDns.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-coredns
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-coredns
+ {{- with .Values.coreDns.serviceMonitor.additionalLabels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ jobLabel: jobLabel
+ selector:
+ matchLabels:
+ app: {{ template "kube-prometheus-stack.name" . }}-coredns
+ release: {{ $.Release.Name | quote }}
+ namespaceSelector:
+ matchNames:
+ - "kube-system"
+ endpoints:
+ - port: http-metrics
+ {{- if .Values.coreDns.serviceMonitor.interval}}
+ interval: {{ .Values.coreDns.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.coreDns.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.coreDns.serviceMonitor.proxyUrl}}
+ {{- end }}
+ bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+{{- if .Values.coreDns.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.coreDns.serviceMonitor.metricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.coreDns.serviceMonitor.relabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.coreDns.serviceMonitor.relabelings | indent 4) . }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/kube-api-server/servicemonitor.yaml b/kube-prometheus-stack/templates/exporters/kube-api-server/servicemonitor.yaml
new file mode 100644
index 00000000..6f83c9bd
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-api-server/servicemonitor.yaml
@@ -0,0 +1,42 @@
+{{- if .Values.kubeApiServer.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-apiserver
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-apiserver
+ {{- with .Values.kubeApiServer.serviceMonitor.additionalLabels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ endpoints:
+ - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+ {{- if .Values.kubeApiServer.serviceMonitor.interval }}
+ interval: {{ .Values.kubeApiServer.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.kubeApiServer.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubeApiServer.serviceMonitor.proxyUrl}}
+ {{- end }}
+ port: https
+ scheme: https
+{{- if .Values.kubeApiServer.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubeApiServer.serviceMonitor.metricRelabelings | indent 6) . }}
+{{- end }}
+{{- if .Values.kubeApiServer.serviceMonitor.relabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubeApiServer.serviceMonitor.relabelings | indent 6) . }}
+{{- end }}
+ tlsConfig:
+ caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ serverName: {{ .Values.kubeApiServer.tlsConfig.serverName }}
+ insecureSkipVerify: {{ .Values.kubeApiServer.tlsConfig.insecureSkipVerify }}
+ jobLabel: {{ .Values.kubeApiServer.serviceMonitor.jobLabel }}
+ namespaceSelector:
+ matchNames:
+ - default
+ selector:
+{{ toYaml .Values.kubeApiServer.serviceMonitor.selector | indent 4 }}
+{{- end}}
diff --git a/kube-prometheus-stack/templates/exporters/kube-controller-manager/endpoints.yaml b/kube-prometheus-stack/templates/exporters/kube-controller-manager/endpoints.yaml
new file mode 100644
index 00000000..eca337da
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-controller-manager/endpoints.yaml
@@ -0,0 +1,22 @@
+{{- if and .Values.kubeControllerManager.enabled .Values.kubeControllerManager.endpoints }}
+apiVersion: v1
+kind: Endpoints
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-controller-manager
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-controller-manager
+ k8s-app: kube-controller-manager
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+ namespace: kube-system
+subsets:
+ - addresses:
+ {{- range .Values.kubeControllerManager.endpoints }}
+ - ip: {{ . }}
+ {{- end }}
+ ports:
+ - name: http-metrics
+ {{- $kubeControllerManagerDefaultInsecurePort := 10252 }}
+ {{- $kubeControllerManagerDefaultSecurePort := 10257 }}
+ port: {{ include "kube-prometheus-stack.kubeControllerManager.insecureScrape" (list . $kubeControllerManagerDefaultInsecurePort $kubeControllerManagerDefaultSecurePort .Values.kubeControllerManager.service.port) }}
+ protocol: TCP
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/kube-controller-manager/service.yaml b/kube-prometheus-stack/templates/exporters/kube-controller-manager/service.yaml
new file mode 100644
index 00000000..197f0f4f
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-controller-manager/service.yaml
@@ -0,0 +1,29 @@
+{{- if and .Values.kubeControllerManager.enabled .Values.kubeControllerManager.service.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-controller-manager
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-controller-manager
+ jobLabel: kube-controller-manager
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+ namespace: kube-system
+spec:
+ clusterIP: None
+ ports:
+ - name: http-metrics
+ {{- $kubeControllerManagerDefaultInsecurePort := 10252 }}
+ {{- $kubeControllerManagerDefaultSecurePort := 10257 }}
+ port: {{ include "kube-prometheus-stack.kubeControllerManager.insecureScrape" (list . $kubeControllerManagerDefaultInsecurePort $kubeControllerManagerDefaultSecurePort .Values.kubeControllerManager.service.port) }}
+ protocol: TCP
+ targetPort: {{ include "kube-prometheus-stack.kubeControllerManager.insecureScrape" (list . $kubeControllerManagerDefaultInsecurePort $kubeControllerManagerDefaultSecurePort .Values.kubeControllerManager.service.targetPort) }}
+{{- if .Values.kubeControllerManager.endpoints }}{{- else }}
+ selector:
+ {{- if .Values.kubeControllerManager.service.selector }}
+{{ toYaml .Values.kubeControllerManager.service.selector | indent 4 }}
+ {{- else}}
+ component: kube-controller-manager
+ {{- end}}
+{{- end }}
+ type: ClusterIP
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/kube-controller-manager/servicemonitor.yaml b/kube-prometheus-stack/templates/exporters/kube-controller-manager/servicemonitor.yaml
new file mode 100644
index 00000000..65556e13
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-controller-manager/servicemonitor.yaml
@@ -0,0 +1,50 @@
+{{- if and .Values.kubeControllerManager.enabled .Values.kubeControllerManager.serviceMonitor.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-controller-manager
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-controller-manager
+ {{- with .Values.kubeControllerManager.serviceMonitor.additionalLabels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ jobLabel: jobLabel
+ selector:
+ matchLabels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-controller-manager
+ release: {{ $.Release.Name | quote }}
+ namespaceSelector:
+ matchNames:
+ - "kube-system"
+ endpoints:
+ - port: http-metrics
+ {{- if .Values.kubeControllerManager.serviceMonitor.interval }}
+ interval: {{ .Values.kubeControllerManager.serviceMonitor.interval }}
+ {{- end }}
+ bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+ {{- if .Values.kubeControllerManager.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubeControllerManager.serviceMonitor.proxyUrl}}
+ {{- end }}
+ {{- if eq (include "kube-prometheus-stack.kubeControllerManager.insecureScrape" (list . false true .Values.kubeControllerManager.serviceMonitor.https )) "true" }}
+ scheme: https
+ tlsConfig:
+ caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ {{- if eq (include "kube-prometheus-stack.kubeControllerManager.insecureScrape" (list . nil true .Values.kubeControllerManager.serviceMonitor.insecureSkipVerify)) "true" }}
+ insecureSkipVerify: true
+ {{- end }}
+ {{- if .Values.kubeControllerManager.serviceMonitor.serverName }}
+ serverName: {{ .Values.kubeControllerManager.serviceMonitor.serverName }}
+ {{- end }}
+ {{- end }}
+{{- if .Values.kubeControllerManager.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubeControllerManager.serviceMonitor.metricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubeControllerManager.serviceMonitor.relabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubeControllerManager.serviceMonitor.relabelings | indent 4) . }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/kube-dns/service.yaml b/kube-prometheus-stack/templates/exporters/kube-dns/service.yaml
new file mode 100644
index 00000000..c7bf142d
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-dns/service.yaml
@@ -0,0 +1,28 @@
+{{- if .Values.kubeDns.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-dns
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-dns
+ jobLabel: kube-dns
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+ namespace: kube-system
+spec:
+ clusterIP: None
+ ports:
+ - name: http-metrics-dnsmasq
+ port: {{ .Values.kubeDns.service.dnsmasq.port }}
+ protocol: TCP
+ targetPort: {{ .Values.kubeDns.service.dnsmasq.targetPort }}
+ - name: http-metrics-skydns
+ port: {{ .Values.kubeDns.service.skydns.port }}
+ protocol: TCP
+ targetPort: {{ .Values.kubeDns.service.skydns.targetPort }}
+ selector:
+ {{- if .Values.kubeDns.service.selector }}
+{{ toYaml .Values.kubeDns.service.selector | indent 4 }}
+ {{- else}}
+ k8s-app: kube-dns
+ {{- end}}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/kube-dns/servicemonitor.yaml b/kube-prometheus-stack/templates/exporters/kube-dns/servicemonitor.yaml
new file mode 100644
index 00000000..5c4afc91
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-dns/servicemonitor.yaml
@@ -0,0 +1,52 @@
+{{- if .Values.kubeDns.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-dns
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-dns
+ {{- with .Values.kubeDns.serviceMonitor.additionalLabels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ jobLabel: jobLabel
+ selector:
+ matchLabels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-dns
+ release: {{ $.Release.Name | quote }}
+ namespaceSelector:
+ matchNames:
+ - "kube-system"
+ endpoints:
+ - port: http-metrics-dnsmasq
+ {{- if .Values.kubeDns.serviceMonitor.interval }}
+ interval: {{ .Values.kubeDns.serviceMonitor.interval }}
+ {{- end }}
+ bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+ {{- if .Values.kubeDns.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubeDns.serviceMonitor.proxyUrl}}
+ {{- end }}
+{{- if .Values.kubeDns.serviceMonitor.dnsmasqMetricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubeDns.serviceMonitor.dnsmasqMetricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubeDns.serviceMonitor.dnsmasqRelabelings }}
+ relabelings:
+{{ toYaml .Values.kubeDns.serviceMonitor.dnsmasqRelabelings | indent 4 }}
+{{- end }}
+ - port: http-metrics-skydns
+ {{- if .Values.kubeDns.serviceMonitor.interval }}
+ interval: {{ .Values.kubeDns.serviceMonitor.interval }}
+ {{- end }}
+ bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+{{- if .Values.kubeDns.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubeDns.serviceMonitor.metricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubeDns.serviceMonitor.relabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubeDns.serviceMonitor.relabelings | indent 4) . }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/kube-etcd/endpoints.yaml b/kube-prometheus-stack/templates/exporters/kube-etcd/endpoints.yaml
new file mode 100644
index 00000000..8f07a5cc
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-etcd/endpoints.yaml
@@ -0,0 +1,20 @@
+{{- if and .Values.kubeEtcd.enabled .Values.kubeEtcd.endpoints }}
+apiVersion: v1
+kind: Endpoints
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-etcd
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-etcd
+ k8s-app: etcd-server
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+ namespace: kube-system
+subsets:
+ - addresses:
+ {{- range .Values.kubeEtcd.endpoints }}
+ - ip: {{ . }}
+ {{- end }}
+ ports:
+ - name: http-metrics
+ port: {{ .Values.kubeEtcd.service.port }}
+ protocol: TCP
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/kube-etcd/service.yaml b/kube-prometheus-stack/templates/exporters/kube-etcd/service.yaml
new file mode 100644
index 00000000..b2677e28
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-etcd/service.yaml
@@ -0,0 +1,27 @@
+{{- if and .Values.kubeEtcd.enabled .Values.kubeEtcd.service.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-etcd
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-etcd
+ jobLabel: kube-etcd
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+ namespace: kube-system
+spec:
+ clusterIP: None
+ ports:
+ - name: http-metrics
+ port: {{ .Values.kubeEtcd.service.port }}
+ protocol: TCP
+ targetPort: {{ .Values.kubeEtcd.service.targetPort }}
+{{- if .Values.kubeEtcd.endpoints }}{{- else }}
+ selector:
+ {{- if .Values.kubeEtcd.service.selector }}
+{{ toYaml .Values.kubeEtcd.service.selector | indent 4 }}
+ {{- else}}
+ component: etcd
+ {{- end}}
+{{- end }}
+ type: ClusterIP
+{{- end -}}
diff --git a/kube-prometheus-stack/templates/exporters/kube-etcd/servicemonitor.yaml b/kube-prometheus-stack/templates/exporters/kube-etcd/servicemonitor.yaml
new file mode 100644
index 00000000..8418c007
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-etcd/servicemonitor.yaml
@@ -0,0 +1,56 @@
+{{- if and .Values.kubeEtcd.enabled .Values.kubeEtcd.serviceMonitor.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-etcd
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-etcd
+ {{- with .Values.kubeEtcd.serviceMonitor.additionalLabels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ jobLabel: jobLabel
+ selector:
+ matchLabels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-etcd
+ release: {{ $.Release.Name | quote }}
+ namespaceSelector:
+ matchNames:
+ - "kube-system"
+ endpoints:
+ - port: http-metrics
+ {{- if .Values.kubeEtcd.serviceMonitor.interval }}
+ interval: {{ .Values.kubeEtcd.serviceMonitor.interval }}
+ {{- end }}
+ bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+ {{- if .Values.kubeEtcd.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubeEtcd.serviceMonitor.proxyUrl}}
+ {{- end }}
+ {{- if eq .Values.kubeEtcd.serviceMonitor.scheme "https" }}
+ scheme: https
+ tlsConfig:
+ {{- if .Values.kubeEtcd.serviceMonitor.serverName }}
+ serverName: {{ .Values.kubeEtcd.serviceMonitor.serverName }}
+ {{- end }}
+ {{- if .Values.kubeEtcd.serviceMonitor.caFile }}
+ caFile: {{ .Values.kubeEtcd.serviceMonitor.caFile }}
+ {{- end }}
+ {{- if .Values.kubeEtcd.serviceMonitor.certFile }}
+ certFile: {{ .Values.kubeEtcd.serviceMonitor.certFile }}
+ {{- end }}
+ {{- if .Values.kubeEtcd.serviceMonitor.keyFile }}
+ keyFile: {{ .Values.kubeEtcd.serviceMonitor.keyFile }}
+ {{- end}}
+ insecureSkipVerify: {{ .Values.kubeEtcd.serviceMonitor.insecureSkipVerify }}
+ {{- end }}
+{{- if .Values.kubeEtcd.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubeEtcd.serviceMonitor.metricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubeEtcd.serviceMonitor.relabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubeEtcd.serviceMonitor.relabelings | indent 4) . }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/kube-proxy/endpoints.yaml b/kube-prometheus-stack/templates/exporters/kube-proxy/endpoints.yaml
new file mode 100644
index 00000000..2cb756d1
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-proxy/endpoints.yaml
@@ -0,0 +1,20 @@
+{{- if and .Values.kubeProxy.enabled .Values.kubeProxy.endpoints }}
+apiVersion: v1
+kind: Endpoints
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-proxy
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-proxy
+ k8s-app: kube-proxy
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+ namespace: kube-system
+subsets:
+ - addresses:
+ {{- range .Values.kubeProxy.endpoints }}
+ - ip: {{ . }}
+ {{- end }}
+ ports:
+ - name: http-metrics
+ port: {{ .Values.kubeProxy.service.port }}
+ protocol: TCP
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/kube-proxy/service.yaml b/kube-prometheus-stack/templates/exporters/kube-proxy/service.yaml
new file mode 100644
index 00000000..6a93319e
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-proxy/service.yaml
@@ -0,0 +1,27 @@
+{{- if and .Values.kubeProxy.enabled .Values.kubeProxy.service.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-proxy
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-proxy
+ jobLabel: kube-proxy
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+ namespace: kube-system
+spec:
+ clusterIP: None
+ ports:
+ - name: http-metrics
+ port: {{ .Values.kubeProxy.service.port }}
+ protocol: TCP
+ targetPort: {{ .Values.kubeProxy.service.targetPort }}
+{{- if .Values.kubeProxy.endpoints }}{{- else }}
+ selector:
+ {{- if .Values.kubeProxy.service.selector }}
+{{ toYaml .Values.kubeProxy.service.selector | indent 4 }}
+ {{- else}}
+ k8s-app: kube-proxy
+ {{- end}}
+{{- end }}
+ type: ClusterIP
+{{- end -}}
diff --git a/kube-prometheus-stack/templates/exporters/kube-proxy/servicemonitor.yaml b/kube-prometheus-stack/templates/exporters/kube-proxy/servicemonitor.yaml
new file mode 100644
index 00000000..329b37b9
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-proxy/servicemonitor.yaml
@@ -0,0 +1,44 @@
+{{- if and .Values.kubeProxy.enabled .Values.kubeProxy.serviceMonitor.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-proxy
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-proxy
+ {{- with .Values.kubeProxy.serviceMonitor.additionalLabels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ jobLabel: jobLabel
+ selector:
+ matchLabels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-proxy
+ release: {{ $.Release.Name | quote }}
+ namespaceSelector:
+ matchNames:
+ - "kube-system"
+ endpoints:
+ - port: http-metrics
+ {{- if .Values.kubeProxy.serviceMonitor.interval }}
+ interval: {{ .Values.kubeProxy.serviceMonitor.interval }}
+ {{- end }}
+ bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+ {{- if .Values.kubeProxy.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubeProxy.serviceMonitor.proxyUrl}}
+ {{- end }}
+ {{- if .Values.kubeProxy.serviceMonitor.https }}
+ scheme: https
+ tlsConfig:
+ caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ {{- end}}
+{{- if .Values.kubeProxy.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubeProxy.serviceMonitor.metricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubeProxy.serviceMonitor.relabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubeProxy.serviceMonitor.relabelings | indent 4) . }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/kube-scheduler/endpoints.yaml b/kube-prometheus-stack/templates/exporters/kube-scheduler/endpoints.yaml
new file mode 100644
index 00000000..84a14ae6
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-scheduler/endpoints.yaml
@@ -0,0 +1,22 @@
+{{- if and .Values.kubeScheduler.enabled .Values.kubeScheduler.endpoints }}
+apiVersion: v1
+kind: Endpoints
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-scheduler
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-scheduler
+ k8s-app: kube-scheduler
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+ namespace: kube-system
+subsets:
+ - addresses:
+ {{- range .Values.kubeScheduler.endpoints }}
+ - ip: {{ . }}
+ {{- end }}
+ ports:
+ - name: http-metrics
+ {{- $kubeSchedulerDefaultInsecurePort := 10251 }}
+ {{- $kubeSchedulerDefaultSecurePort := 10259 }}
+ port: {{ include "kube-prometheus-stack.kubeScheduler.insecureScrape" (list . $kubeSchedulerDefaultInsecurePort $kubeSchedulerDefaultSecurePort .Values.kubeScheduler.service.port) }}
+ protocol: TCP
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/kube-scheduler/service.yaml b/kube-prometheus-stack/templates/exporters/kube-scheduler/service.yaml
new file mode 100644
index 00000000..eef9df01
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-scheduler/service.yaml
@@ -0,0 +1,29 @@
+{{- if and .Values.kubeScheduler.enabled .Values.kubeScheduler.service.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-scheduler
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-scheduler
+ jobLabel: kube-scheduler
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+ namespace: kube-system
+spec:
+ clusterIP: None
+ ports:
+ - name: http-metrics
+ {{- $kubeSchedulerDefaultInsecurePort := 10251 }}
+ {{- $kubeSchedulerDefaultSecurePort := 10259 }}
+ port: {{ include "kube-prometheus-stack.kubeScheduler.insecureScrape" (list . $kubeSchedulerDefaultInsecurePort $kubeSchedulerDefaultSecurePort .Values.kubeScheduler.service.port) }}
+ protocol: TCP
+ targetPort: {{ include "kube-prometheus-stack.kubeScheduler.insecureScrape" (list . $kubeSchedulerDefaultInsecurePort $kubeSchedulerDefaultSecurePort .Values.kubeScheduler.service.targetPort) }}
+{{- if .Values.kubeScheduler.endpoints }}{{- else }}
+ selector:
+ {{- if .Values.kubeScheduler.service.selector }}
+{{ toYaml .Values.kubeScheduler.service.selector | indent 4 }}
+ {{- else}}
+ component: kube-scheduler
+ {{- end}}
+{{- end }}
+ type: ClusterIP
+{{- end -}}
diff --git a/kube-prometheus-stack/templates/exporters/kube-scheduler/servicemonitor.yaml b/kube-prometheus-stack/templates/exporters/kube-scheduler/servicemonitor.yaml
new file mode 100644
index 00000000..6d43bf6f
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kube-scheduler/servicemonitor.yaml
@@ -0,0 +1,50 @@
+{{- if and .Values.kubeScheduler.enabled .Values.kubeScheduler.serviceMonitor.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kube-scheduler
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-scheduler
+ {{- with .Values.kubeScheduler.serviceMonitor.additionalLabels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ jobLabel: jobLabel
+ selector:
+ matchLabels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kube-scheduler
+ release: {{ $.Release.Name | quote }}
+ namespaceSelector:
+ matchNames:
+ - "kube-system"
+ endpoints:
+ - port: http-metrics
+ {{- if .Values.kubeScheduler.serviceMonitor.interval }}
+ interval: {{ .Values.kubeScheduler.serviceMonitor.interval }}
+ {{- end }}
+ bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+ {{- if .Values.kubeScheduler.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubeScheduler.serviceMonitor.proxyUrl}}
+ {{- end }}
+ {{- if eq (include "kube-prometheus-stack.kubeScheduler.insecureScrape" (list . false true .Values.kubeScheduler.serviceMonitor.https )) "true" }}
+ scheme: https
+ tlsConfig:
+ caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ {{- if eq (include "kube-prometheus-stack.kubeScheduler.insecureScrape" (list . nil true .Values.kubeScheduler.serviceMonitor.insecureSkipVerify)) "true" }}
+ insecureSkipVerify: true
+ {{- end }}
+ {{- if .Values.kubeScheduler.serviceMonitor.serverName }}
+ serverName: {{ .Values.kubeScheduler.serviceMonitor.serverName }}
+ {{- end}}
+ {{- end}}
+{{- if .Values.kubeScheduler.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubeScheduler.serviceMonitor.metricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubeScheduler.serviceMonitor.relabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubeScheduler.serviceMonitor.relabelings | indent 4) . }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/exporters/kubelet/servicemonitor.yaml b/kube-prometheus-stack/templates/exporters/kubelet/servicemonitor.yaml
new file mode 100644
index 00000000..52700bc7
--- /dev/null
+++ b/kube-prometheus-stack/templates/exporters/kubelet/servicemonitor.yaml
@@ -0,0 +1,216 @@
+{{- if .Values.kubelet.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-kubelet
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-kubelet
+ {{- with .Values.kubelet.serviceMonitor.additionalLabels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{- include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ endpoints:
+ {{- if .Values.kubelet.serviceMonitor.https }}
+ - port: https-metrics
+ scheme: https
+ {{- if .Values.kubelet.serviceMonitor.interval }}
+ interval: {{ .Values.kubelet.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ {{- end }}
+ tlsConfig:
+ caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ insecureSkipVerify: true
+ bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+ honorLabels: true
+{{- if .Values.kubelet.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.metricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.relabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.relabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.cAdvisor }}
+ - port: https-metrics
+ scheme: https
+ path: /metrics/cadvisor
+ {{- if .Values.kubelet.serviceMonitor.interval }}
+ interval: {{ .Values.kubelet.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ {{- end }}
+ honorLabels: true
+ tlsConfig:
+ caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ insecureSkipVerify: true
+ bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+{{- if .Values.kubelet.serviceMonitor.cAdvisorMetricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.cAdvisorMetricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.cAdvisorRelabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.cAdvisorRelabelings | indent 4) . }}
+{{- end }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.probes }}
+ - port: https-metrics
+ scheme: https
+ path: /metrics/probes
+ {{- if .Values.kubelet.serviceMonitor.interval }}
+ interval: {{ .Values.kubelet.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ {{- end }}
+ honorLabels: true
+ tlsConfig:
+ caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ insecureSkipVerify: true
+ bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+{{- if .Values.kubelet.serviceMonitor.probesMetricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.probesMetricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.probesRelabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.probesRelabelings | indent 4) . }}
+{{- end }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.resource }}
+ - port: https-metrics
+ scheme: https
+ path: {{ .Values.kubelet.serviceMonitor.resourcePath }}
+ {{- if .Values.kubelet.serviceMonitor.interval }}
+ interval: {{ .Values.kubelet.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ {{- end }}
+ honorLabels: true
+ tlsConfig:
+ caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
+ insecureSkipVerify: true
+ bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
+{{- if .Values.kubelet.serviceMonitor.resourceMetricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.resourceMetricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.resourceRelabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.resourceRelabelings | indent 4) . }}
+{{- end }}
+{{- end }}
+ {{- else }}
+ - port: http-metrics
+ {{- if .Values.kubelet.serviceMonitor.interval }}
+ interval: {{ .Values.kubelet.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ {{- end }}
+ honorLabels: true
+{{- if .Values.kubelet.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.metricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.relabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.relabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.cAdvisor }}
+ - port: http-metrics
+ path: /metrics/cadvisor
+ {{- if .Values.kubelet.serviceMonitor.interval }}
+ interval: {{ .Values.kubelet.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ {{- end }}
+ honorLabels: true
+{{- if .Values.kubelet.serviceMonitor.cAdvisorMetricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.cAdvisorMetricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.cAdvisorRelabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.cAdvisorRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.probes }}
+ - port: http-metrics
+ path: /metrics/probes
+ {{- if .Values.kubelet.serviceMonitor.interval }}
+ interval: {{ .Values.kubelet.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ {{- end }}
+ honorLabels: true
+{{- if .Values.kubelet.serviceMonitor.probesMetricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.probesMetricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.probesRelabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.probesRelabelings | indent 4) . }}
+{{- end }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.resource }}
+ - port: http-metrics
+ path: {{ .Values.kubelet.serviceMonitor.resourcePath }}
+ {{- if .Values.kubelet.serviceMonitor.interval }}
+ interval: {{ .Values.kubelet.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }}
+ {{- end }}
+ {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }}
+ {{- end }}
+ honorLabels: true
+{{- if .Values.kubelet.serviceMonitor.resourceMetricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.resourceMetricRelabelings | indent 4) . }}
+{{- end }}
+{{- if .Values.kubelet.serviceMonitor.resourceRelabelings }}
+ relabelings:
+{{ tpl (toYaml .Values.kubelet.serviceMonitor.resourceRelabelings | indent 4) . }}
+{{- end }}
+{{- end }}
+{{- end }}
+ {{- end }}
+ jobLabel: k8s-app
+ namespaceSelector:
+ matchNames:
+ - {{ .Values.kubelet.namespace }}
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: kubelet
+ k8s-app: kubelet
+{{- end}}
diff --git a/kube-prometheus-stack/templates/grafana/configmap-dashboards.yaml b/kube-prometheus-stack/templates/grafana/configmap-dashboards.yaml
new file mode 100644
index 00000000..c04efc42
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/configmap-dashboards.yaml
@@ -0,0 +1,24 @@
+{{- if or (and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled) .Values.grafana.forceDeployDashboards }}
+{{- $files := .Files.Glob "dashboards-1.14/*.json" }}
+{{- if $files }}
+apiVersion: v1
+kind: ConfigMapList
+items:
+{{- range $path, $fileContents := $files }}
+{{- $dashboardName := regexReplaceAll "(^.*/)(.*)\\.json$" $path "${2}" }}
+- apiVersion: v1
+ kind: ConfigMap
+ metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) $dashboardName | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" $ }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 6 }}
+ data:
+ {{ $dashboardName }}.json: {{ $.Files.Get $path | toJson }}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/grafana/configmaps-datasources.yaml b/kube-prometheus-stack/templates/grafana/configmaps-datasources.yaml
new file mode 100644
index 00000000..b5f0bf8f
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/configmaps-datasources.yaml
@@ -0,0 +1,63 @@
+{{- if or (and .Values.grafana.enabled .Values.grafana.sidecar.datasources.enabled) .Values.grafana.forceDeployDatasources }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-grafana-datasource
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+{{- if .Values.grafana.sidecar.datasources.annotations }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.datasources.annotations | indent 4 }}
+{{- end }}
+ labels:
+ {{ $.Values.grafana.sidecar.datasources.label }}: {{ $.Values.grafana.sidecar.datasources.labelValue | quote }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ datasource.yaml: |-
+ apiVersion: 1
+{{- if .Values.grafana.deleteDatasources }}
+ deleteDatasources:
+{{ tpl (toYaml .Values.grafana.deleteDatasources | indent 6) . }}
+{{- end }}
+ datasources:
+{{- $scrapeInterval := .Values.grafana.sidecar.datasources.defaultDatasourceScrapeInterval | default .Values.prometheus.prometheusSpec.scrapeInterval | default "30s" }}
+{{- if .Values.grafana.sidecar.datasources.defaultDatasourceEnabled }}
+ - name: Prometheus
+ type: prometheus
+ uid: {{ .Values.grafana.sidecar.datasources.uid }}
+ {{- if .Values.grafana.sidecar.datasources.url }}
+ url: {{ .Values.grafana.sidecar.datasources.url }}
+ {{- else }}
+ url: http://{{ template "kube-prometheus-stack.fullname" . }}-prometheus.{{ template "kube-prometheus-stack.namespace" . }}:{{ .Values.prometheus.service.port }}/{{ trimPrefix "/" .Values.prometheus.prometheusSpec.routePrefix }}
+ {{- end }}
+ access: proxy
+ isDefault: true
+ jsonData:
+ timeInterval: {{ $scrapeInterval }}
+{{- if .Values.grafana.sidecar.datasources.exemplarTraceIdDestinations }}
+ exemplarTraceIdDestinations:
+ - datasourceUid: {{ .Values.grafana.sidecar.datasources.exemplarTraceIdDestinations.datasourceUid }}
+ name: {{ .Values.grafana.sidecar.datasources.exemplarTraceIdDestinations.traceIdLabelName }}
+{{- end }}
+{{- if .Values.grafana.sidecar.datasources.createPrometheusReplicasDatasources }}
+{{- range until (int .Values.prometheus.prometheusSpec.replicas) }}
+ - name: Prometheus-{{ . }}
+ type: prometheus
+ uid: {{ $.Values.grafana.sidecar.datasources.uid }}-replica-{{ . }}
+ url: http://prometheus-{{ template "kube-prometheus-stack.prometheus.crname" $ }}-{{ . }}.prometheus-operated:9090/{{ trimPrefix "/" $.Values.prometheus.prometheusSpec.routePrefix }}
+ access: proxy
+ isDefault: false
+ jsonData:
+ timeInterval: {{ $scrapeInterval }}
+{{- if $.Values.grafana.sidecar.datasources.exemplarTraceIdDestinations }}
+ exemplarTraceIdDestinations:
+ - datasourceUid: {{ .Values.grafana.sidecar.datasources.exemplarTraceIdDestinations.datasourceUid }}
+ name: {{ .Values.grafana.sidecar.datasources.exemplarTraceIdDestinations.traceIdLabelName }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- if .Values.grafana.additionalDataSources }}
+{{ tpl (toYaml .Values.grafana.additionalDataSources | indent 4) . }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/alertmanager-overview.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/alertmanager-overview.yaml
new file mode 100644
index 00000000..7236239b
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/alertmanager-overview.yaml
@@ -0,0 +1,614 @@
+{{- /*
+Generated from 'alertmanager-overview' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "alertmanager-overview" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ alertmanager-overview.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": false,
+ "gnetId": null,
+ "graphTooltip": 1,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "refresh": "30s",
+ "rows": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "current set of alerts stored in the Alertmanager",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 2,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(alertmanager_alerts{namespace=~\"$namespace\",service=~\"$service\"}) by (namespace,service,instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Alerts",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "none",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "none",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "rate of successful and invalid alerts received by the Alertmanager",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 3,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(alertmanager_alerts_received_total{namespace=~\"$namespace\",service=~\"$service\"}[$__rate_interval])) by (namespace,service,instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Received",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(rate(alertmanager_alerts_invalid_total{namespace=~\"$namespace\",service=~\"$service\"}[$__rate_interval])) by (namespace,service,instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Invalid",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Alerts receive rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Alerts",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "rate of successful and invalid notifications sent by the Alertmanager",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 4,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": "integration",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(alertmanager_notifications_total{namespace=~\"$namespace\",service=~\"$service\", integration=\"$integration\"}[$__rate_interval])) by (integration,namespace,service,instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Total",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(rate(alertmanager_notifications_failed_total{namespace=~\"$namespace\",service=~\"$service\", integration=\"$integration\"}[$__rate_interval])) by (integration,namespace,service,instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Failed",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "$integration: Notifications Send Rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "latency of notifications sent by the Alertmanager",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 5,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": "integration",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99,\n sum(rate(alertmanager_notification_latency_seconds_bucket{namespace=~\"$namespace\",service=~\"$service\", integration=\"$integration\"}[$__rate_interval])) by (le,namespace,service,instance)\n) \n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} 99th Percentile",
+ "refId": "A"
+ },
+ {
+ "expr": "histogram_quantile(0.50,\n sum(rate(alertmanager_notification_latency_seconds_bucket{namespace=~\"$namespace\",service=~\"$service\", integration=\"$integration\"}[$__rate_interval])) by (le,namespace,service,instance)\n) \n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Median",
+ "refId": "B"
+ },
+ {
+ "expr": "sum(rate(alertmanager_notification_latency_seconds_sum{namespace=~\"$namespace\",service=~\"$service\", integration=\"$integration\"}[$__rate_interval])) by (namespace,service,instance)\n/\nsum(rate(alertmanager_notification_latency_seconds_count{namespace=~\"$namespace\",service=~\"$service\", integration=\"$integration\"}[$__rate_interval])) by (namespace,service,instance)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Average",
+ "refId": "C"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "$integration: Notification Duration",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Notifications",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "alertmanager-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "Prometheus",
+ "value": "Prometheus"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": "namespace",
+ "multi": false,
+ "name": "namespace",
+ "options": [
+
+ ],
+ "query": "label_values(alertmanager_alerts, namespace)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": "service",
+ "multi": false,
+ "name": "service",
+ "options": [
+
+ ],
+ "query": "label_values(alertmanager_alerts, service)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "all",
+ "value": "$__all"
+ },
+ "datasource": "$datasource",
+ "hide": 2,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "integration",
+ "options": [
+
+ ],
+ "query": "label_values(alertmanager_notifications_total{integration=~\".*\"}, integration)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Alertmanager / Overview",
+ "uid": "alertmanager-overview",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/apiserver.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/apiserver.yaml
new file mode 100644
index 00000000..4b9fe4b8
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/apiserver.yaml
@@ -0,0 +1,1772 @@
+{{- /*
+Generated from 'apiserver' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.kubeApiServer.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "apiserver" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ apiserver.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": false,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "panels": [
+ {
+ "content": "The SLO (service level objective) and other metrics displayed on this dashboard are for informational purposes only.",
+ "datasource": null,
+ "description": "The SLO (service level objective) and other metrics displayed on this dashboard are for informational purposes only.",
+ "gridPos": {
+ "h": 2,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 2,
+ "mode": "markdown",
+ "span": 12,
+ "title": "Notice",
+ "type": "text"
+ }
+ ],
+ "refresh": "10s",
+ "rows": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "$datasource",
+ "decimals": 3,
+ "description": "How many percent of requests (both read and write) in 30 days have been answered successfully and fast enough?",
+ "format": "percentunit",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+
+ },
+ "id": 3,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "rightSide": true
+ },
+ "links": [
+
+ ],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 4,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "apiserver_request:availability30d{verb=\"all\", cluster=\"$cluster\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Availability (30d) > 99.000%",
+ "tooltip": {
+ "shared": false
+ },
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "avg"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "decimals": 3,
+ "description": "How much error budget is left looking at our 0.990% availability guarantees?",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 4,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 8,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "100 * (apiserver_request:availability30d{verb=\"all\", cluster=\"$cluster\"} - 0.990000)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "errorbudget",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "ErrorBudget (30d) > 99.000%",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "decimals": 3,
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "decimals": 3,
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "$datasource",
+ "decimals": 3,
+ "description": "How many percent of read requests (LIST,GET) in 30 days have been answered successfully and fast enough?",
+ "format": "percentunit",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+
+ },
+ "id": 5,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "rightSide": true
+ },
+ "links": [
+
+ ],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 3,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "apiserver_request:availability30d{verb=\"read\", cluster=\"$cluster\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Read Availability (30d)",
+ "tooltip": {
+ "shared": false
+ },
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "avg"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "How many read requests (LIST,GET) per second do the apiservers get by code?",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 6,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+ {
+ "alias": "/2../i",
+ "color": "#56A64B"
+ },
+ {
+ "alias": "/3../i",
+ "color": "#F2CC0C"
+ },
+ {
+ "alias": "/4../i",
+ "color": "#3274D9"
+ },
+ {
+ "alias": "/5../i",
+ "color": "#E02F44"
+ }
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum by (code) (code_resource:apiserver_request_total:rate5m{verb=\"read\", cluster=\"$cluster\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}} code {{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Read SLI - Requests",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "reqps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "reqps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "How many percent of read requests (LIST,GET) per second are returned with errors (5xx)?",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 7,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum by (resource) (code_resource:apiserver_request_total:rate5m{verb=\"read\",code=~\"5..\", cluster=\"$cluster\"}) / sum by (resource) (code_resource:apiserver_request_total:rate5m{verb=\"read\", cluster=\"$cluster\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}} resource {{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Read SLI - Errors",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "How many seconds is the 99th percentile for reading (LIST|GET) a given resource?",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 8,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "cluster_quantile:apiserver_request_slo_duration_seconds:histogram_quantile{verb=\"read\", cluster=\"$cluster\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}} resource {{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Read SLI - Duration",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "$datasource",
+ "decimals": 3,
+ "description": "How many percent of write requests (POST|PUT|PATCH|DELETE) in 30 days have been answered successfully and fast enough?",
+ "format": "percentunit",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+
+ },
+ "id": 9,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "rightSide": true
+ },
+ "links": [
+
+ ],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 3,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "apiserver_request:availability30d{verb=\"write\", cluster=\"$cluster\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Write Availability (30d)",
+ "tooltip": {
+ "shared": false
+ },
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "avg"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "How many write requests (POST|PUT|PATCH|DELETE) per second do the apiservers get by code?",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 10,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+ {
+ "alias": "/2../i",
+ "color": "#56A64B"
+ },
+ {
+ "alias": "/3../i",
+ "color": "#F2CC0C"
+ },
+ {
+ "alias": "/4../i",
+ "color": "#3274D9"
+ },
+ {
+ "alias": "/5../i",
+ "color": "#E02F44"
+ }
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum by (code) (code_resource:apiserver_request_total:rate5m{verb=\"write\", cluster=\"$cluster\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}} code {{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Write SLI - Requests",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "reqps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "reqps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "How many percent of write requests (POST|PUT|PATCH|DELETE) per second are returned with errors (5xx)?",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 11,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum by (resource) (code_resource:apiserver_request_total:rate5m{verb=\"write\",code=~\"5..\", cluster=\"$cluster\"}) / sum by (resource) (code_resource:apiserver_request_total:rate5m{verb=\"write\", cluster=\"$cluster\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}} resource {{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Write SLI - Errors",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "How many seconds is the 99th percentile for writing (POST|PUT|PATCH|DELETE) a given resource?",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 12,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "cluster_quantile:apiserver_request_slo_duration_seconds:histogram_quantile{verb=\"write\", cluster=\"$cluster\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}} resource {{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Write SLI - Duration",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 13,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(workqueue_adds_total{job=\"apiserver\", instance=~\"$instance\", cluster=\"$cluster\"}[$__rate_interval])) by (instance, name)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}name{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Work Queue Add Rate",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 14,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(workqueue_depth{job=\"apiserver\", instance=~\"$instance\", cluster=\"$cluster\"}[$__rate_interval])) by (instance, name)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}name{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Work Queue Depth",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 15,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(workqueue_queue_duration_seconds_bucket{job=\"apiserver\", instance=~\"$instance\", cluster=\"$cluster\"}[$__rate_interval])) by (instance, name, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}name{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Work Queue Latency",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 16,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "process_resident_memory_bytes{job=\"apiserver\",instance=~\"$instance\", cluster=\"$cluster\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 17,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(process_cpu_seconds_total{job=\"apiserver\",instance=~\"$instance\", cluster=\"$cluster\"}[$__rate_interval])",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 18,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "go_goroutines{job=\"apiserver\",instance=~\"$instance\", cluster=\"$cluster\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Goroutines",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": "cluster",
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"apiserver\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "instance",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"apiserver\", cluster=\"$cluster\"}, instance)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / API server",
+ "uid": "09ec8aa1e996d6ffcd6817bbaff4db1b",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/cluster-total.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/cluster-total.yaml
new file mode 100644
index 00000000..16c18727
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/cluster-total.yaml
@@ -0,0 +1,1882 @@
+{{- /*
+Generated from 'cluster-total' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "cluster-total" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ cluster-total.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "panels": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 2,
+ "panels": [
+
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Current Bandwidth",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": true,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 1
+ },
+ "id": 3,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": false,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Rate of Bytes Received",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "series",
+ "name": null,
+ "show": false,
+ "values": [
+ "current"
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": true,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 1
+ },
+ "id": 4,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": false,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Rate of Bytes Transmitted",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "series",
+ "name": null,
+ "show": false,
+ "values": [
+ "current"
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "columns": [
+ {
+ "text": "Time",
+ "value": "Time"
+ },
+ {
+ "text": "Value #A",
+ "value": "Value #A"
+ },
+ {
+ "text": "Value #B",
+ "value": "Value #B"
+ },
+ {
+ "text": "Value #C",
+ "value": "Value #C"
+ },
+ {
+ "text": "Value #D",
+ "value": "Value #D"
+ },
+ {
+ "text": "Value #E",
+ "value": "Value #E"
+ },
+ {
+ "text": "Value #F",
+ "value": "Value #F"
+ },
+ {
+ "text": "Value #G",
+ "value": "Value #G"
+ },
+ {
+ "text": "Value #H",
+ "value": "Value #H"
+ },
+ {
+ "text": "namespace",
+ "value": "namespace"
+ }
+ ],
+ "datasource": "$datasource",
+ "fill": 1,
+ "fontSize": "90%",
+ "gridPos": {
+ "h": 9,
+ "w": 24,
+ "x": 0,
+ "y": 10
+ },
+ "id": 5,
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null as zero",
+ "renderer": "flot",
+ "scroll": true,
+ "showHeader": true,
+ "sort": {
+ "col": 0,
+ "desc": false
+ },
+ "spaceLength": 10,
+ "span": 24,
+ "styles": [
+ {
+ "alias": "Time",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Time",
+ "thresholds": [
+
+ ],
+ "type": "hidden",
+ "unit": "short"
+ },
+ {
+ "alias": "Current Bandwidth Received",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Current Bandwidth Transmitted",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Average Bandwidth Received",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Average Bandwidth Transmitted",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Rate of Received Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Received Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #G",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #H",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Namespace",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTooltip": "Drill down",
+ "linkUrl": "d/8b7a8b326d7a6f1f04244066368c67af/kubernetes-networking-namespace-pods?orgId=1&refresh=30s&var-namespace=$__cell",
+ "pattern": "namespace",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(avg(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(avg(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "G",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "H",
+ "step": 10
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Status",
+ "type": "table"
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 10
+ },
+ "id": 6,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": true,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 11
+ },
+ "id": 7,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": false,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(avg(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Rate of Bytes Received",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "series",
+ "name": null,
+ "show": false,
+ "values": [
+ "current"
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": true,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 11
+ },
+ "id": 8,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": false,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(avg(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Rate of Bytes Transmitted",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "series",
+ "name": null,
+ "show": false,
+ "values": [
+ "current"
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Average Bandwidth",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 11
+ },
+ "id": 9,
+ "panels": [
+
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Bandwidth History",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 24,
+ "x": 0,
+ "y": 12
+ },
+ "id": 10,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": true,
+ "min": true,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Receive Bandwidth",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 24,
+ "x": 0,
+ "y": 21
+ },
+ "id": 11,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": true,
+ "min": true,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Transmit Bandwidth",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 30
+ },
+ "id": 12,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 24,
+ "x": 0,
+ "y": 31
+ },
+ "id": 13,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": true,
+ "min": true,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 24,
+ "x": 0,
+ "y": 40
+ },
+ "id": 14,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": true,
+ "min": true,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Packets",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 31
+ },
+ "id": 15,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 24,
+ "x": 0,
+ "y": 50
+ },
+ "id": 16,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": true,
+ "min": true,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets Dropped",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 24,
+ "x": 0,
+ "y": 59
+ },
+ "id": 17,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": true,
+ "min": true,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets Dropped",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 24,
+ "x": 0,
+ "y": 59
+ },
+ "id": 18,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": true,
+ "min": true,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+ {
+ "targetBlank": true,
+ "title": "What is TCP Retransmit?",
+ "url": "https://accedian.com/enterprises/blog/network-packet-loss-retransmissions-and-duplicate-acknowledgements/"
+ }
+ ],
+ "minSpan": 24,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(rate(node_netstat_Tcp_RetransSegs{cluster=\"$cluster\"}[$interval:$resolution]) / rate(node_netstat_Tcp_OutSegs{cluster=\"$cluster\"}[$interval:$resolution])) by (instance))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of TCP Retransmits out of all sent segments",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 24,
+ "x": 0,
+ "y": 59
+ },
+ "id": 19,
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": true,
+ "min": true,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+ {
+ "targetBlank": true,
+ "title": "Why monitor SYN retransmits?",
+ "url": "https://github.com/prometheus/node_exporter/issues/1023#issuecomment-408128365"
+ }
+ ],
+ "minSpan": 24,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(rate(node_netstat_TcpExt_TCPSynRetrans{cluster=\"$cluster\"}[$interval:$resolution]) / rate(node_netstat_Tcp_RetransSegs{cluster=\"$cluster\"}[$interval:$resolution])) by (instance))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of TCP SYN Retransmits out of all retransmits",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Errors",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "refresh": "10s",
+ "rows": [
+
+ ],
+ "schemaVersion": 18,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "5m",
+ "value": "5m"
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "resolution",
+ "options": [
+ {
+ "selected": false,
+ "text": "30s",
+ "value": "30s"
+ },
+ {
+ "selected": true,
+ "text": "5m",
+ "value": "5m"
+ },
+ {
+ "selected": false,
+ "text": "1h",
+ "value": "1h"
+ }
+ ],
+ "query": "30s,5m,1h",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "interval",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "5m",
+ "value": "5m"
+ },
+ "datasource": "$datasource",
+ "hide": 2,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "interval",
+ "options": [
+ {
+ "selected": true,
+ "text": "4h",
+ "value": "4h"
+ }
+ ],
+ "query": "4h",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "interval",
+ "useTags": false
+ },
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Networking / Cluster",
+ "uid": "ff635a025bcfea7bc3dd4f508990a3e9",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/controller-manager.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/controller-manager.yaml
new file mode 100644
index 00000000..5d687e87
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/controller-manager.yaml
@@ -0,0 +1,1190 @@
+{{- /*
+Generated from 'controller-manager' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.kubeControllerManager.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "controller-manager" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ controller-manager.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": false,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "refresh": "10s",
+ "rows": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "$datasource",
+ "format": "none",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+
+ },
+ "id": 2,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "rightSide": true
+ },
+ "links": [
+
+ ],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 2,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(up{cluster=\"$cluster\", job=\"kube-controller-manager\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Up",
+ "tooltip": {
+ "shared": false
+ },
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "min"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 3,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(workqueue_adds_total{cluster=\"$cluster\", job=\"kube-controller-manager\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, name)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} {{`{{`}}name{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Work Queue Add Rate",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 4,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(workqueue_depth{cluster=\"$cluster\", job=\"kube-controller-manager\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, name)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} {{`{{`}}name{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Work Queue Depth",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 5,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(workqueue_queue_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-controller-manager\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, name, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} {{`{{`}}name{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Work Queue Latency",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 6,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(rest_client_requests_total{job=\"kube-controller-manager\", instance=~\"$instance\",code=~\"2..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "2xx",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(rate(rest_client_requests_total{job=\"kube-controller-manager\", instance=~\"$instance\",code=~\"3..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "3xx",
+ "refId": "B"
+ },
+ {
+ "expr": "sum(rate(rest_client_requests_total{job=\"kube-controller-manager\", instance=~\"$instance\",code=~\"4..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "4xx",
+ "refId": "C"
+ },
+ {
+ "expr": "sum(rate(rest_client_requests_total{job=\"kube-controller-manager\", instance=~\"$instance\",code=~\"5..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "5xx",
+ "refId": "D"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Kube API Request Rate",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 7,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 8,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-controller-manager\", instance=~\"$instance\", verb=\"POST\"}[$__rate_interval])) by (verb, url, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Post Request Latency 99th Quantile",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 8,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-controller-manager\", instance=~\"$instance\", verb=\"GET\"}[$__rate_interval])) by (verb, url, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Get Request Latency 99th Quantile",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 9,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "process_resident_memory_bytes{cluster=\"$cluster\", job=\"kube-controller-manager\",instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 10,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(process_cpu_seconds_total{cluster=\"$cluster\", job=\"kube-controller-manager\",instance=~\"$instance\"}[$__rate_interval])",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 11,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "go_goroutines{cluster=\"$cluster\", job=\"kube-controller-manager\",instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Goroutines",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": "cluster",
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kube-controller-manager\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "instance",
+ "options": [
+
+ ],
+ "query": "label_values(up{cluster=\"$cluster\", job=\"kube-controller-manager\"}, instance)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Controller Manager",
+ "uid": "72e0e05bef5099e5f049b05fdc429ed4",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/etcd.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/etcd.yaml
new file mode 100644
index 00000000..aeda5331
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/etcd.yaml
@@ -0,0 +1,1227 @@
+{{- /*
+Generated from 'etcd' from https://raw.githubusercontent.com/etcd-io/etcd/main/contrib/mixin/mixin.libsonnet
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.kubeEtcd.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "etcd" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ etcd.json: |-
+ {
+ "annotations": {
+ "list": []
+ },
+ "description": "etcd sample Grafana dashboard with Prometheus",
+ "editable": true,
+ "gnetId": null,
+ "hideControls": false,
+ "links": [],
+ "refresh": "10s",
+ "rows": [
+ {
+ "collapse": false,
+ "editable": true,
+ "height": "250px",
+ "panels": [
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "rgba(245, 54, 54, 0.9)",
+ "rgba(237, 129, 40, 0.89)",
+ "rgba(50, 172, 45, 0.97)"
+ ],
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "format": "none",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "id": 28,
+ "interval": null,
+ "isNew": true,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 3,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "targets": [
+ {
+ "expr": "sum(etcd_server_has_leader{job=\"$cluster\"})",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "metric": "etcd_server_has_leader",
+ "refId": "A",
+ "step": 20
+ }
+ ],
+ "thresholds": "",
+ "title": "Up",
+ "type": "singlestat",
+ "valueFontSize": "200%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "avg"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fill": 0,
+ "id": 23,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 5,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(grpc_server_started_total{job=\"$cluster\",grpc_type=\"unary\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "RPC Rate",
+ "metric": "grpc_server_started_total",
+ "refId": "A",
+ "step": 2
+ },
+ {
+ "expr": "sum(rate(grpc_server_handled_total{job=\"$cluster\",grpc_type=\"unary\",grpc_code=~\"Unknown|FailedPrecondition|ResourceExhausted|Internal|Unavailable|DataLoss|DeadlineExceeded\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "RPC Failed Rate",
+ "metric": "grpc_server_handled_total",
+ "refId": "B",
+ "step": 2
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "RPC Rate",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fill": 0,
+ "id": 41,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 4,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(grpc_server_started_total{job=\"$cluster\",grpc_service=\"etcdserverpb.Watch\",grpc_type=\"bidi_stream\"}) - sum(grpc_server_handled_total{job=\"$cluster\",grpc_service=\"etcdserverpb.Watch\",grpc_type=\"bidi_stream\"})",
+ "intervalFactor": 2,
+ "legendFormat": "Watch Streams",
+ "metric": "grpc_server_handled_total",
+ "refId": "A",
+ "step": 4
+ },
+ {
+ "expr": "sum(grpc_server_started_total{job=\"$cluster\",grpc_service=\"etcdserverpb.Lease\",grpc_type=\"bidi_stream\"}) - sum(grpc_server_handled_total{job=\"$cluster\",grpc_service=\"etcdserverpb.Lease\",grpc_type=\"bidi_stream\"})",
+ "intervalFactor": 2,
+ "legendFormat": "Lease Streams",
+ "metric": "grpc_server_handled_total",
+ "refId": "B",
+ "step": 4
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Active Streams",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": "",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "showTitle": false,
+ "title": "Row"
+ },
+ {
+ "collapse": false,
+ "editable": true,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": "$datasource",
+ "decimals": null,
+ "editable": true,
+ "error": false,
+ "fill": 0,
+ "grid": {},
+ "id": 1,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "etcd_mvcc_db_total_size_in_bytes{job=\"$cluster\"}",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} DB Size",
+ "metric": "",
+ "refId": "A",
+ "step": 4
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "DB Size",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fill": 0,
+ "grid": {},
+ "id": 3,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 1,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 4,
+ "stack": false,
+ "steppedLine": true,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(etcd_disk_wal_fsync_duration_seconds_bucket{job=\"$cluster\"}[$__rate_interval])) by (instance, le))",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} WAL fsync",
+ "metric": "etcd_disk_wal_fsync_duration_seconds_bucket",
+ "refId": "A",
+ "step": 4
+ },
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(etcd_disk_backend_commit_duration_seconds_bucket{job=\"$cluster\"}[$__rate_interval])) by (instance, le))",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} DB fsync",
+ "metric": "etcd_disk_backend_commit_duration_seconds_bucket",
+ "refId": "B",
+ "step": 4
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Disk Sync Duration",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fill": 0,
+ "id": 29,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "process_resident_memory_bytes{job=\"$cluster\"}",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Resident Memory",
+ "metric": "process_resident_memory_bytes",
+ "refId": "A",
+ "step": 4
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "title": "New row"
+ },
+ {
+ "collapse": false,
+ "editable": true,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fill": 5,
+ "id": 22,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 3,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(etcd_network_client_grpc_received_bytes_total{job=\"$cluster\"}[$__rate_interval])",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Client Traffic In",
+ "metric": "etcd_network_client_grpc_received_bytes_total",
+ "refId": "A",
+ "step": 4
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Client Traffic In",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fill": 5,
+ "id": 21,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 3,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(etcd_network_client_grpc_sent_bytes_total{job=\"$cluster\"}[$__rate_interval])",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Client Traffic Out",
+ "metric": "etcd_network_client_grpc_sent_bytes_total",
+ "refId": "A",
+ "step": 4
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Client Traffic Out",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fill": 0,
+ "id": 20,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(etcd_network_peer_received_bytes_total{job=\"$cluster\"}[$__rate_interval])) by (instance)",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Peer Traffic In",
+ "metric": "etcd_network_peer_received_bytes_total",
+ "refId": "A",
+ "step": 4
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Peer Traffic In",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": "$datasource",
+ "decimals": null,
+ "editable": true,
+ "error": false,
+ "fill": 0,
+ "grid": {},
+ "id": 16,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(etcd_network_peer_sent_bytes_total{job=\"$cluster\"}[$__rate_interval])) by (instance)",
+ "hide": false,
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Peer Traffic Out",
+ "metric": "etcd_network_peer_sent_bytes_total",
+ "refId": "A",
+ "step": 4
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Peer Traffic Out",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "title": "New row"
+ },
+ {
+ "collapse": false,
+ "editable": true,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fill": 0,
+ "id": 40,
+ "isNew": true,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(etcd_server_proposals_failed_total{job=\"$cluster\"}[$__rate_interval]))",
+ "intervalFactor": 2,
+ "legendFormat": "Proposal Failure Rate",
+ "metric": "etcd_server_proposals_failed_total",
+ "refId": "A",
+ "step": 2
+ },
+ {
+ "expr": "sum(etcd_server_proposals_pending{job=\"$cluster\"})",
+ "intervalFactor": 2,
+ "legendFormat": "Proposal Pending Total",
+ "metric": "etcd_server_proposals_pending",
+ "refId": "B",
+ "step": 2
+ },
+ {
+ "expr": "sum(rate(etcd_server_proposals_committed_total{job=\"$cluster\"}[$__rate_interval]))",
+ "intervalFactor": 2,
+ "legendFormat": "Proposal Commit Rate",
+ "metric": "etcd_server_proposals_committed_total",
+ "refId": "C",
+ "step": 2
+ },
+ {
+ "expr": "sum(rate(etcd_server_proposals_applied_total{job=\"$cluster\"}[$__rate_interval]))",
+ "intervalFactor": 2,
+ "legendFormat": "Proposal Apply Rate",
+ "refId": "D",
+ "step": 2
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Raft Proposals",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": "",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "datasource": "$datasource",
+ "decimals": 0,
+ "editable": true,
+ "error": false,
+ "fill": 0,
+ "id": 19,
+ "isNew": true,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "changes(etcd_server_leader_changes_seen_total{job=\"$cluster\"}[1d])",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Total Leader Elections Per Day",
+ "metric": "etcd_server_leader_changes_seen_total",
+ "refId": "A",
+ "step": 2
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Total Leader Elections Per Day",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "decimals": 0,
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {}
+ },
+ "overrides": []
+ },
+ "fill": 0,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 0,
+ "y": 28
+ },
+ "hiddenSeries": false,
+ "id": 42,
+ "isNew": true,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.4.3",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum by (instance, le) (rate(etcd_network_peer_round_trip_time_seconds_bucket{job=\"$cluster\"}[$__rate_interval])))",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Peer round trip time",
+ "metric": "etcd_network_peer_round_trip_time_seconds_bucket",
+ "refId": "A",
+ "step": 2
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Peer round trip time",
+ "tooltip": {
+ "msResolution": false,
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "$$hashKey": "object:925",
+ "decimals": null,
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "$$hashKey": "object:926",
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ }
+ ],
+ "title": "New row"
+ }
+ ],
+ "schemaVersion": 13,
+ "sharedCrosshair": false,
+ "style": "dark",
+ "tags": [
+ "etcd-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "Prometheus",
+ "value": "Prometheus"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "prod",
+ "value": "prod"
+ },
+ "datasource": "$datasource",
+ "hide": {{ if (or .Values.grafana.sidecar.dashboards.multicluster.global.enabled .Values.grafana.sidecar.dashboards.multicluster.etcd.enabled) }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": "cluster",
+ "multi": false,
+ "name": "cluster",
+ "options": [],
+ "query": "label_values(etcd_server_has_leader, job)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 2,
+ "tagValuesQuery": "",
+ "tags": [],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-15m",
+ "to": "now"
+ },
+ "timepicker": {
+ "now": true,
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "etcd",
+ "uid": "c2f4e12cdf69feb95caa41a5a1b423d9",
+ "version": 215
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/grafana-overview.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/grafana-overview.yaml
new file mode 100644
index 00000000..decbf0b1
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/grafana-overview.yaml
@@ -0,0 +1,636 @@
+{{- /*
+Generated from 'grafana-overview' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "grafana-overview" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ grafana-overview.json: |-
+ {
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "target": {
+ "limit": 100,
+ "matchAny": false,
+ "tags": [
+
+ ],
+ "type": "dashboard"
+ },
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "id": 3085,
+ "iteration": 1631554945276,
+ "links": [
+
+ ],
+ "panels": [
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "mappings": [
+
+ ],
+ "noValue": "0",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": [
+
+ ]
+ },
+ "gridPos": {
+ "h": 5,
+ "w": 6,
+ "x": 0,
+ "y": 0
+ },
+ "id": 6,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "area",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "mean"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {
+
+ },
+ "textMode": "auto"
+ },
+ "pluginVersion": "8.1.3",
+ "targets": [
+ {
+ "expr": "grafana_alerting_result_total{job=~\"$job\", instance=~\"$instance\", state=\"alerting\"}",
+ "instant": true,
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Firing Alerts",
+ "type": "stat"
+ },
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "mappings": [
+
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": [
+
+ ]
+ },
+ "gridPos": {
+ "h": 5,
+ "w": 6,
+ "x": 6,
+ "y": 0
+ },
+ "id": 8,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "area",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "mean"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {
+
+ },
+ "textMode": "auto"
+ },
+ "pluginVersion": "8.1.3",
+ "targets": [
+ {
+ "expr": "sum(grafana_stat_totals_dashboard{job=~\"$job\", instance=~\"$instance\"})",
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Dashboards",
+ "type": "stat"
+ },
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "custom": {
+ "align": null,
+ "displayMode": "auto"
+ },
+ "mappings": [
+
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": [
+
+ ]
+ },
+ "gridPos": {
+ "h": 5,
+ "w": 12,
+ "x": 12,
+ "y": 0
+ },
+ "id": 10,
+ "options": {
+ "showHeader": true
+ },
+ "pluginVersion": "8.1.3",
+ "targets": [
+ {
+ "expr": "grafana_build_info{job=~\"$job\", instance=~\"$instance\"}",
+ "instant": true,
+ "interval": "",
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Build Info",
+ "transformations": [
+ {
+ "id": "labelsToFields",
+ "options": {
+
+ }
+ },
+ {
+ "id": "organize",
+ "options": {
+ "excludeByName": {
+ "Time": true,
+ "Value": true,
+ "branch": true,
+ "container": true,
+ "goversion": true,
+ "namespace": true,
+ "pod": true,
+ "revision": true
+ },
+ "indexByName": {
+ "Time": 7,
+ "Value": 11,
+ "branch": 4,
+ "container": 8,
+ "edition": 2,
+ "goversion": 6,
+ "instance": 1,
+ "job": 0,
+ "namespace": 9,
+ "pod": 10,
+ "revision": 5,
+ "version": 3
+ },
+ "renameByName": {
+
+ }
+ }
+ }
+ ],
+ "type": "table"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "links": [
+
+ ]
+ },
+ "overrides": [
+
+ ]
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 0,
+ "y": 5
+ },
+ "hiddenSeries": false,
+ "id": 2,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "8.1.3",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum by (status_code) (irate(grafana_http_request_duration_seconds_count{job=~\"$job\", instance=~\"$instance\"}[1m])) ",
+ "interval": "",
+ "legendFormat": "{{`{{`}}status_code{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeRegions": [
+
+ ],
+ "timeShift": null,
+ "title": "RPS",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "$$hashKey": "object:157",
+ "format": "reqps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "$$hashKey": "object:158",
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "links": [
+
+ ]
+ },
+ "overrides": [
+
+ ]
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 12,
+ "y": 5
+ },
+ "hiddenSeries": false,
+ "id": 4,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "nullPointMode": "null",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "8.1.3",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "exemplar": true,
+ "expr": "histogram_quantile(0.99, sum(irate(grafana_http_request_duration_seconds_bucket{instance=~\"$instance\", job=~\"$job\"}[$__rate_interval])) by (le)) * 1",
+ "interval": "",
+ "legendFormat": "99th Percentile",
+ "refId": "A"
+ },
+ {
+ "exemplar": true,
+ "expr": "histogram_quantile(0.50, sum(irate(grafana_http_request_duration_seconds_bucket{instance=~\"$instance\", job=~\"$job\"}[$__rate_interval])) by (le)) * 1",
+ "interval": "",
+ "legendFormat": "50th Percentile",
+ "refId": "B"
+ },
+ {
+ "exemplar": true,
+ "expr": "sum(irate(grafana_http_request_duration_seconds_sum{instance=~\"$instance\", job=~\"$job\"}[$__rate_interval])) * 1 / sum(irate(grafana_http_request_duration_seconds_count{instance=~\"$instance\", job=~\"$job\"}[$__rate_interval]))",
+ "interval": "",
+ "legendFormat": "Average",
+ "refId": "C"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeRegions": [
+
+ ],
+ "timeShift": null,
+ "title": "Request Latency",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "$$hashKey": "object:210",
+ "format": "ms",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "$$hashKey": "object:211",
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ }
+ ],
+ "schemaVersion": 30,
+ "style": "dark",
+ "tags": [
+
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "selected": true,
+ "text": "dev-cortex",
+ "value": "dev-cortex"
+ },
+ "description": null,
+ "error": null,
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "queryValue": "",
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "type": "datasource"
+ },
+ {
+ "allValue": ".*",
+ "current": {
+ "selected": false,
+ "text": [
+ "default/grafana"
+ ],
+ "value": [
+ "default/grafana"
+ ]
+ },
+ "datasource": "$datasource",
+ "definition": "label_values(grafana_build_info, job)",
+ "description": null,
+ "error": null,
+ "hide": 0,
+ "includeAll": true,
+ "label": null,
+ "multi": true,
+ "name": "job",
+ "options": [
+
+ ],
+ "query": {
+ "query": "label_values(grafana_build_info, job)",
+ "refId": "Billing Admin-job-Variable-Query"
+ },
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": ".*",
+ "current": {
+ "selected": false,
+ "text": "All",
+ "value": "$__all"
+ },
+ "datasource": "$datasource",
+ "definition": "label_values(grafana_build_info, instance)",
+ "description": null,
+ "error": null,
+ "hide": 0,
+ "includeAll": true,
+ "label": null,
+ "multi": true,
+ "name": "instance",
+ "options": [
+
+ ],
+ "query": {
+ "query": "label_values(grafana_build_info, instance)",
+ "refId": "Billing Admin-instance-Variable-Query"
+ },
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-6h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Grafana Overview",
+ "uid": "6be0s85Mk",
+ "version": 2
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-coredns.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-coredns.yaml
new file mode 100644
index 00000000..4a1846c8
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-coredns.yaml
@@ -0,0 +1,1531 @@
+{{- /* Added manually, can be changed in-place. */ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.coreDns.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-coredns" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ k8s-coredns.json: |-
+ {
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "type": "dashboard"
+ }
+ ]
+ },
+ "description": "A dashboard for the CoreDNS DNS server with updated metrics for version 1.7.0+. Based on the CoreDNS dashboard by buhay.",
+ "editable": true,
+ "gnetId": 12539,
+ "graphTooltip": 0,
+ "iteration": 1603798405693,
+ "links": [
+ {
+ "icon": "external link",
+ "tags": [],
+ "targetBlank": true,
+ "title": "CoreDNS.io",
+ "type": "link",
+ "url": "https://coredns.io"
+ }
+ ],
+ "panels": [
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {},
+ "links": [],
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "grid": {},
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 0
+ },
+ "hiddenSeries": false,
+ "id": 2,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.2.0",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "total",
+ "yaxis": 2
+ }
+ ],
+ "spaceLength": 10,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(coredns_dns_request_count_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (proto) or\nsum(rate(coredns_dns_requests_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (proto)",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}",
+ "refId": "A",
+ "step": 60
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Requests (total)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {},
+ "links": []
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "grid": {},
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 8,
+ "y": 0
+ },
+ "hiddenSeries": false,
+ "id": 4,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.2.0",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "total",
+ "yaxis": 2
+ },
+ {
+ "alias": "other",
+ "yaxis": 2
+ }
+ ],
+ "spaceLength": 10,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(coredns_dns_request_type_count_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (type) or \nsum(rate(coredns_dns_requests_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (type)",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{type}}"}}",
+ "refId": "A",
+ "step": 60
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Requests (by qtype)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {},
+ "links": []
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "grid": {},
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 16,
+ "y": 0
+ },
+ "hiddenSeries": false,
+ "id": 6,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.2.0",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "total",
+ "yaxis": 2
+ }
+ ],
+ "spaceLength": 10,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(coredns_dns_request_count_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (zone) or\nsum(rate(coredns_dns_requests_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (zone)",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{zone}}"}}",
+ "refId": "A",
+ "step": 60
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Requests (by zone)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {},
+ "links": []
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "grid": {},
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 0,
+ "y": 7
+ },
+ "hiddenSeries": false,
+ "id": 8,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.2.0",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "total",
+ "yaxis": 2
+ }
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(coredns_dns_request_do_count_total{job=\"coredns\",instance=~\"$instance\"}[5m])) or\nsum(rate(coredns_dns_do_requests_total{job=\"coredns\",instance=~\"$instance\"}[5m]))",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "DO",
+ "refId": "A",
+ "step": 40
+ },
+ {
+ "expr": "sum(rate(coredns_dns_request_count_total{job=\"coredns\",instance=~\"$instance\"}[5m])) or\nsum(rate(coredns_dns_requests_total{job=\"coredns\",instance=~\"$instance\"}[5m]))",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "total",
+ "refId": "B",
+ "step": 40
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Requests (DO bit)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {},
+ "links": []
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "grid": {},
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 12,
+ "y": 7
+ },
+ "hiddenSeries": false,
+ "id": 10,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.2.0",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "tcp:90",
+ "yaxis": 2
+ },
+ {
+ "alias": "tcp:99 ",
+ "yaxis": 2
+ },
+ {
+ "alias": "tcp:50",
+ "yaxis": 2
+ }
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(coredns_dns_request_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"udp\"}[5m])) by (le,proto))",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}:99 ",
+ "refId": "A",
+ "step": 60
+ },
+ {
+ "expr": "histogram_quantile(0.90, sum(rate(coredns_dns_request_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"udp\"}[5m])) by (le,proto))",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}:90",
+ "refId": "B",
+ "step": 60
+ },
+ {
+ "expr": "histogram_quantile(0.50, sum(rate(coredns_dns_request_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"udp\"}[5m])) by (le,proto))",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}:50",
+ "refId": "C",
+ "step": 60
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Requests (size, udp)",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {},
+ "links": []
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "grid": {},
+ "gridPos": {
+ "h": 7,
+ "w": 6,
+ "x": 18,
+ "y": 7
+ },
+ "hiddenSeries": false,
+ "id": 12,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.2.0",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "tcp:90",
+ "yaxis": 1
+ },
+ {
+ "alias": "tcp:99 ",
+ "yaxis": 1
+ },
+ {
+ "alias": "tcp:50",
+ "yaxis": 1
+ }
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(coredns_dns_request_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"tcp\"}[5m])) by (le,proto))",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}:99 ",
+ "refId": "A",
+ "step": 60
+ },
+ {
+ "expr": "histogram_quantile(0.90, sum(rate(coredns_dns_request_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"tcp\"}[5m])) by (le,proto))",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}:90",
+ "refId": "B",
+ "step": 60
+ },
+ {
+ "expr": "histogram_quantile(0.50, sum(rate(coredns_dns_request_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"tcp\"}[5m])) by (le,proto))",
+ "format": "time_series",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}:50",
+ "refId": "C",
+ "step": 60
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Requests (size,tcp)",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {},
+ "links": []
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "grid": {},
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 0,
+ "y": 14
+ },
+ "hiddenSeries": false,
+ "id": 14,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.2.0",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(coredns_dns_response_rcode_count_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (rcode) or\nsum(rate(coredns_dns_responses_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (rcode)",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{rcode}}"}}",
+ "refId": "A",
+ "step": 40
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Responses (by rcode)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {},
+ "links": []
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "grid": {},
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 12,
+ "y": 14
+ },
+ "hiddenSeries": false,
+ "id": 32,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.2.0",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(coredns_dns_request_duration_seconds_bucket{job=\"coredns\",instance=~\"$instance\"}[5m])) by (le, job))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "99%",
+ "refId": "A",
+ "step": 40
+ },
+ {
+ "expr": "histogram_quantile(0.90, sum(rate(coredns_dns_request_duration_seconds_bucket{job=\"coredns\",instance=~\"$instance\"}[5m])) by (le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "90%",
+ "refId": "B",
+ "step": 40
+ },
+ {
+ "expr": "histogram_quantile(0.50, sum(rate(coredns_dns_request_duration_seconds_bucket{job=\"coredns\",instance=~\"$instance\"}[5m])) by (le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "50%",
+ "refId": "C",
+ "step": 40
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Responses (duration)",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {},
+ "links": []
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "grid": {},
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 0,
+ "y": 21
+ },
+ "hiddenSeries": false,
+ "id": 18,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.2.0",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "udp:50%",
+ "yaxis": 1
+ },
+ {
+ "alias": "tcp:50%",
+ "yaxis": 2
+ },
+ {
+ "alias": "tcp:90%",
+ "yaxis": 2
+ },
+ {
+ "alias": "tcp:99%",
+ "yaxis": 2
+ }
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(coredns_dns_response_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"udp\"}[5m])) by (le,proto)) ",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}:99%",
+ "refId": "A",
+ "step": 40
+ },
+ {
+ "expr": "histogram_quantile(0.90, sum(rate(coredns_dns_response_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"udp\"}[5m])) by (le,proto)) ",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}:90%",
+ "refId": "B",
+ "step": 40
+ },
+ {
+ "expr": "histogram_quantile(0.50, sum(rate(coredns_dns_response_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"udp\"}[5m])) by (le,proto)) ",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}:50%",
+ "metric": "",
+ "refId": "C",
+ "step": 40
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Responses (size, udp)",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {},
+ "links": []
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "grid": {},
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 12,
+ "y": 21
+ },
+ "hiddenSeries": false,
+ "id": 20,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.2.0",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "udp:50%",
+ "yaxis": 1
+ },
+ {
+ "alias": "tcp:50%",
+ "yaxis": 1
+ },
+ {
+ "alias": "tcp:90%",
+ "yaxis": 1
+ },
+ {
+ "alias": "tcp:99%",
+ "yaxis": 1
+ }
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(coredns_dns_response_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"tcp\"}[5m])) by (le,proto)) ",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}:99%",
+ "refId": "A",
+ "step": 40
+ },
+ {
+ "expr": "histogram_quantile(0.90, sum(rate(coredns_dns_response_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"tcp\"}[5m])) by (le,proto)) ",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}:90%",
+ "refId": "B",
+ "step": 40
+ },
+ {
+ "expr": "histogram_quantile(0.50, sum(rate(coredns_dns_response_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"tcp\"}[5m])) by (le, proto)) ",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{proto}}"}}:50%",
+ "metric": "",
+ "refId": "C",
+ "step": 40
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Responses (size, tcp)",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {},
+ "links": []
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "grid": {},
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 0,
+ "y": 28
+ },
+ "hiddenSeries": false,
+ "id": 22,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.2.0",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(coredns_cache_size{job=\"coredns\",instance=~\"$instance\"}) by (type) or\nsum(coredns_cache_entries{job=\"coredns\",instance=~\"$instance\"}) by (type)",
+ "interval": "",
+ "intervalFactor": 2,
+ "legendFormat": "{{"{{type}}"}}",
+ "refId": "A",
+ "step": 40
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Cache (size)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "cumulative"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "decbytes",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "editable": true,
+ "error": false,
+ "fieldConfig": {
+ "defaults": {
+ "custom": {},
+ "links": []
+ },
+ "overrides": []
+ },
+ "fill": 1,
+ "fillGradient": 0,
+ "grid": {},
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 12,
+ "y": 28
+ },
+ "hiddenSeries": false,
+ "id": 24,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [],
+ "nullPointMode": "connected",
+ "options": {
+ "alertThreshold": true
+ },
+ "percentage": false,
+ "pluginVersion": "7.2.0",
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "misses",
+ "yaxis": 2
+ }
+ ],
+ "spaceLength": 10,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(coredns_cache_hits_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (type)",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "hits:{{"{{type}}"}}",
+ "refId": "A",
+ "step": 40
+ },
+ {
+ "expr": "sum(rate(coredns_cache_misses_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (type)",
+ "hide": false,
+ "intervalFactor": 2,
+ "legendFormat": "misses",
+ "refId": "B",
+ "step": 40
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Cache (hitrate)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ }
+ ],
+ "refresh": "10s",
+ "schemaVersion": 26,
+ "style": "dark",
+ "tags": [
+ "dns",
+ "coredns"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "selected": true,
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "datasource",
+ "options": [],
+ "query": "prometheus",
+ "queryValue": "",
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "type": "datasource"
+ },
+ {
+ "allValue": ".*",
+ "current": {
+ "selected": true,
+ "text": "All",
+ "value": "$__all"
+ },
+ "datasource": "$datasource",
+ "definition": "label_values(up{job=\"coredns\"}, instance)",
+ "hide": 0,
+ "includeAll": true,
+ "label": "Instance",
+ "multi": false,
+ "name": "instance",
+ "options": [],
+ "query": "label_values(up{job=\"coredns\"}, instance)",
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 3,
+ "tagValuesQuery": "",
+ "tags": [],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-3h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "CoreDNS",
+ "uid": "vkQ0UHxik",
+ "version": 2
+ }
+{{- end }}
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-cluster.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-cluster.yaml
new file mode 100644
index 00000000..b6b3e1d4
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-cluster.yaml
@@ -0,0 +1,3088 @@
+{{- /*
+Generated from 'k8s-resources-cluster' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-cluster" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ k8s-resources-cluster.json: |-
+ {
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "links": [
+
+ ],
+ "refresh": "10s",
+ "rows": [
+ {
+ "collapse": false,
+ "height": "100px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "format": "percentunit",
+ "id": 1,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 2,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "cluster:node_cpu:ratio_rate5m{cluster=\"$cluster\"}",
+ "format": "time_series",
+ "instant": true,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "70,80",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Utilisation",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "singlestat",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "format": "percentunit",
+ "id": 2,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 2,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(namespace_cpu:kube_pod_container_resource_requests:sum{cluster=\"$cluster\"}) / sum(kube_node_status_allocatable{job=\"kube-state-metrics\",resource=\"cpu\",cluster=\"$cluster\"})",
+ "format": "time_series",
+ "instant": true,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "70,80",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Requests Commitment",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "singlestat",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "format": "percentunit",
+ "id": 3,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 2,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(namespace_cpu:kube_pod_container_resource_limits:sum{cluster=\"$cluster\"}) / sum(kube_node_status_allocatable{job=\"kube-state-metrics\",resource=\"cpu\",cluster=\"$cluster\"})",
+ "format": "time_series",
+ "instant": true,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "70,80",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Limits Commitment",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "singlestat",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "format": "percentunit",
+ "id": 4,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 2,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "1 - sum(:node_memory_MemAvailable_bytes:sum{cluster=\"$cluster\"}) / sum(node_memory_MemTotal_bytes{job=\"node-exporter\",cluster=\"$cluster\"})",
+ "format": "time_series",
+ "instant": true,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "70,80",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Utilisation",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "singlestat",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "format": "percentunit",
+ "id": 5,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 2,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(namespace_memory:kube_pod_container_resource_requests:sum{cluster=\"$cluster\"}) / sum(kube_node_status_allocatable{job=\"kube-state-metrics\",resource=\"memory\",cluster=\"$cluster\"})",
+ "format": "time_series",
+ "instant": true,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "70,80",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Requests Commitment",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "singlestat",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "format": "percentunit",
+ "id": 6,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 2,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(namespace_memory:kube_pod_container_resource_limits:sum{cluster=\"$cluster\"}) / sum(kube_node_status_allocatable{job=\"kube-state-metrics\",resource=\"memory\",cluster=\"$cluster\"})",
+ "format": "time_series",
+ "instant": true,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "70,80",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Limits Commitment",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "singlestat",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Headlines",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 7,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\"}) by (namespace)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 8,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Pods",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 0,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down to pods",
+ "linkUrl": "/d/85a562078cdf77779eaa1add43ccec1e/k8s-resources-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell_1",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Workloads",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 0,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down to workloads",
+ "linkUrl": "/d/a87fb0d919ec0ea5f6543124e16c42a5/k8s-resources-workloads-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell_1",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Usage",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Requests",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Requests %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "CPU Limits",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Limits %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #G",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Namespace",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down to pods",
+ "linkUrl": "/d/85a562078cdf77779eaa1add43ccec1e/k8s-resources-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell",
+ "pattern": "namespace",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(kube_pod_owner{job=\"kube-state-metrics\", cluster=\"$cluster\"}) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "count(avg(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\"}) by (workload, namespace)) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\"}) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(namespace_cpu:kube_pod_container_resource_requests:sum{cluster=\"$cluster\"}) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\"}) by (namespace) / sum(namespace_cpu:kube_pod_container_resource_requests:sum{cluster=\"$cluster\"}) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum(namespace_cpu:kube_pod_container_resource_limits:sum{cluster=\"$cluster\"}) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\"}) by (namespace) / sum(namespace_cpu:kube_pod_container_resource_limits:sum{cluster=\"$cluster\"}) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "G",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Quota",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU Quota",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 9,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(container_memory_rss{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", container!=\"\"}) by (namespace)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Usage (w/o cache)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 10,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Pods",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 0,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down to pods",
+ "linkUrl": "/d/85a562078cdf77779eaa1add43ccec1e/k8s-resources-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell_1",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Workloads",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 0,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down to workloads",
+ "linkUrl": "/d/a87fb0d919ec0ea5f6543124e16c42a5/k8s-resources-workloads-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell_1",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Memory Usage",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Requests",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Requests %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Memory Limits",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Limits %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #G",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Namespace",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down to pods",
+ "linkUrl": "/d/85a562078cdf77779eaa1add43ccec1e/k8s-resources-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell",
+ "pattern": "namespace",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(kube_pod_owner{job=\"kube-state-metrics\", cluster=\"$cluster\"}) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "count(avg(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\"}) by (workload, namespace)) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_rss{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", container!=\"\"}) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(namespace_memory:kube_pod_container_resource_requests:sum{cluster=\"$cluster\"}) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_rss{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", container!=\"\"}) by (namespace) / sum(namespace_memory:kube_pod_container_resource_requests:sum{cluster=\"$cluster\"}) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum(namespace_memory:kube_pod_container_resource_limits:sum{cluster=\"$cluster\"}) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_rss{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", container!=\"\"}) by (namespace) / sum(namespace_memory:kube_pod_container_resource_limits:sum{cluster=\"$cluster\"}) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "G",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Requests by Namespace",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory Requests",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 11,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Current Receive Bandwidth",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Current Transmit Bandwidth",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Rate of Received Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Received Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Namespace",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down to pods",
+ "linkUrl": "/d/85a562078cdf77779eaa1add43ccec1e/k8s-resources-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell",
+ "pattern": "namespace",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_receive_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_transmit_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_receive_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_transmit_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Network Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Current Network Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 12,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Receive Bandwidth",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 13,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Transmit Bandwidth",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Bandwidth",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 14,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "avg(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Container Bandwidth by Namespace: Received",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 15,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "avg(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Container Bandwidth by Namespace: Transmitted",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Average Container Bandwidth by Namespace",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 16,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 17,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Rate of Packets",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 18,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets Dropped",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 19,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets Dropped",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Rate of Packets Dropped",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "decimals": -1,
+ "fill": 10,
+ "id": 20,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "ceil(sum by(namespace) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval])))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "IOPS(Reads+Writes)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 21,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum by(namespace) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}namespace{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "ThroughPut(Read+Write)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Storage IO",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 22,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "sort": {
+ "col": 4,
+ "desc": true
+ },
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "IOPS(Reads)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": -1,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "IOPS(Writes)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": -1,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "IOPS(Reads + Writes)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": -1,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Throughput(Read)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Throughput(Write)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Throughput(Read + Write)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Namespace",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down to pods",
+ "linkUrl": "/d/85a562078cdf77779eaa1add43ccec1e/k8s-resources-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell",
+ "pattern": "namespace",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum by(namespace) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum by(namespace) (rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum by(namespace) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum by(namespace) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum by(namespace) (rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum by(namespace) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Storage IO",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Storage IO - Distribution",
+ "titleSize": "h6"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Compute Resources / Cluster",
+ "uid": "efa86fd1d0c121a26444b636a3f509a8",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-namespace.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-namespace.yaml
new file mode 100644
index 00000000..9151a288
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-namespace.yaml
@@ -0,0 +1,2797 @@
+{{- /*
+Generated from 'k8s-resources-namespace' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-namespace" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ k8s-resources-namespace.json: |-
+ {
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "links": [
+
+ ],
+ "refresh": "10s",
+ "rows": [
+ {
+ "collapse": false,
+ "height": "100px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "format": "percentunit",
+ "id": 1,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}) / sum(kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"})",
+ "format": "time_series",
+ "instant": true,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "70,80",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Utilisation (from requests)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "singlestat",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "format": "percentunit",
+ "id": 2,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}) / sum(kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"})",
+ "format": "time_series",
+ "instant": true,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "70,80",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Utilisation (from limits)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "singlestat",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "format": "percentunit",
+ "id": 3,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\", image!=\"\"}) / sum(kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"})",
+ "format": "time_series",
+ "instant": true,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "70,80",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Utilisation (from requests)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "singlestat",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "format": "percentunit",
+ "id": 4,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\", image!=\"\"}) / sum(kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"})",
+ "format": "time_series",
+ "instant": true,
+ "intervalFactor": 2,
+ "refId": "A"
+ }
+ ],
+ "thresholds": "70,80",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Utilisation (from limits)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "singlestat",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Headlines",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 5,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "quota - requests",
+ "color": "#F2495C",
+ "dashes": true,
+ "fill": 0,
+ "hiddenSeries": true,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ },
+ {
+ "alias": "quota - limits",
+ "color": "#FF9830",
+ "dashes": true,
+ "fill": 0,
+ "hiddenSeries": true,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ }
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"requests.cpu\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "quota - requests",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"limits.cpu\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "quota - limits",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 6,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "CPU Usage",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Requests",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Requests %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "CPU Limits",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Limits %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Pod",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "/d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell",
+ "pattern": "pod",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Quota",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU Quota",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 7,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "quota - requests",
+ "color": "#F2495C",
+ "dashes": true,
+ "fill": 0,
+ "hiddenSeries": true,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ },
+ {
+ "alias": "quota - limits",
+ "color": "#FF9830",
+ "dashes": true,
+ "fill": 0,
+ "hiddenSeries": true,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ }
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"requests.memory\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "quota - requests",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"limits.memory\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "quota - limits",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Usage (w/o cache)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 8,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Memory Usage",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Requests",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Requests %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Memory Limits",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Limits %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Memory Usage (RSS)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Usage (Cache)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #G",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Usage (Swap)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #H",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Pod",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "/d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell",
+ "pattern": "pod",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\", image!=\"\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\", image!=\"\"}) by (pod) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\", image!=\"\"}) by (pod) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_rss{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_cache{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "G",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_swap{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "H",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Quota",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory Quota",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 9,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Current Receive Bandwidth",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Current Transmit Bandwidth",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Rate of Received Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Received Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Pod",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down to pods",
+ "linkUrl": "/d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell",
+ "pattern": "pod",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_receive_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_transmit_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_receive_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_transmit_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Network Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Current Network Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 10,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Receive Bandwidth",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 11,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Transmit Bandwidth",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Bandwidth",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 12,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_packets_total{cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 13,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Rate of Packets",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 14,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets Dropped",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 15,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets Dropped",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Rate of Packets Dropped",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "decimals": -1,
+ "fill": 10,
+ "id": 16,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "ceil(sum by(pod) (rate(container_fs_reads_total{container!=\"\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]) + rate(container_fs_writes_total{container!=\"\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "IOPS(Reads+Writes)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 17,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum by(pod) (rate(container_fs_reads_bytes_total{container!=\"\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{container!=\"\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "ThroughPut(Read+Write)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Storage IO",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 18,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "sort": {
+ "col": 4,
+ "desc": true
+ },
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "IOPS(Reads)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": -1,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "IOPS(Writes)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": -1,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "IOPS(Reads + Writes)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": -1,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Throughput(Read)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Throughput(Write)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Throughput(Read + Write)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Pod",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down to pods",
+ "linkUrl": "/d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell",
+ "pattern": "pod",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum by(pod) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum by(pod) (rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum by(pod) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum by(pod) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum by(pod) (rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum by(pod) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Storage IO",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Storage IO - Distribution",
+ "titleSize": "h6"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kube-state-metrics\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "namespace",
+ "options": [
+
+ ],
+ "query": "label_values(kube_namespace_status_phase{job=\"kube-state-metrics\", cluster=\"$cluster\"}, namespace)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Compute Resources / Namespace (Pods)",
+ "uid": "85a562078cdf77779eaa1add43ccec1e",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-node.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-node.yaml
new file mode 100644
index 00000000..93668129
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-node.yaml
@@ -0,0 +1,1026 @@
+{{- /*
+Generated from 'k8s-resources-node' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-node" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ k8s-resources-node.json: |-
+ {
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "links": [
+
+ ],
+ "refresh": "10s",
+ "rows": [
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 1,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "max capacity",
+ "color": "#F2495C",
+ "dashes": true,
+ "fill": 0,
+ "hiddenSeries": true,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ }
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(kube_node_status_capacity{cluster=\"$cluster\", node=~\"$node\", resource=\"cpu\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "max capacity",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", node=~\"$node\"}) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 2,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "CPU Usage",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Requests",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Requests %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "CPU Limits",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Limits %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Pod",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "pod",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", node=~\"$node\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", node=~\"$node\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", node=~\"$node\"}) by (pod) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", node=~\"$node\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", node=~\"$node\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", node=~\"$node\"}) by (pod) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", node=~\"$node\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Quota",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU Quota",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 3,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "max capacity",
+ "color": "#F2495C",
+ "dashes": true,
+ "fill": 0,
+ "hiddenSeries": true,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ }
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(kube_node_status_capacity{cluster=\"$cluster\", node=~\"$node\", resource=\"memory\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "max capacity",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_memory_working_set_bytes{cluster=\"$cluster\", node=~\"$node\", container!=\"\"}) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Usage (w/o cache)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 4,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Memory Usage",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Requests",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Requests %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Memory Limits",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Limits %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Memory Usage (RSS)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Usage (Cache)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #G",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Usage (Swap)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #H",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Pod",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "pod",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(node_namespace_pod_container:container_memory_working_set_bytes{cluster=\"$cluster\", node=~\"$node\",container!=\"\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", node=~\"$node\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_memory_working_set_bytes{cluster=\"$cluster\", node=~\"$node\",container!=\"\"}) by (pod) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", node=~\"$node\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", node=~\"$node\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_memory_working_set_bytes{cluster=\"$cluster\", node=~\"$node\",container!=\"\"}) by (pod) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", node=~\"$node\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_memory_rss{cluster=\"$cluster\", node=~\"$node\",container!=\"\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_memory_cache{cluster=\"$cluster\", node=~\"$node\",container!=\"\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "G",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_memory_swap{cluster=\"$cluster\", node=~\"$node\",container!=\"\"}) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "H",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Quota",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory Quota",
+ "titleSize": "h6"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kube-state-metrics\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": true,
+ "name": "node",
+ "options": [
+
+ ],
+ "query": "label_values(kube_node_info{cluster=\"$cluster\"}, node)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Compute Resources / Node (Pods)",
+ "uid": "200ac8fdbfbb74b39aff88118e4d1c2c",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-pod.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-pod.yaml
new file mode 100644
index 00000000..4efba703
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-pod.yaml
@@ -0,0 +1,2469 @@
+{{- /*
+Generated from 'k8s-resources-pod' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-pod" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ k8s-resources-pod.json: |-
+ {
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "links": [
+
+ ],
+ "refresh": "10s",
+ "rows": [
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 1,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "requests",
+ "color": "#F2495C",
+ "fill": 0,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ },
+ {
+ "alias": "limits",
+ "color": "#FF9830",
+ "fill": 0,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ }
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\", pod=\"$pod\", cluster=\"$cluster\"}) by (container)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}container{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", resource=\"cpu\"}\n)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "requests",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", resource=\"cpu\"}\n)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "limits",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 2,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": true,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(increase(container_cpu_cfs_throttled_periods_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", cluster=\"$cluster\"}[$__rate_interval])) by (container) /sum(increase(container_cpu_cfs_periods_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", cluster=\"$cluster\"}[$__rate_interval])) by (container)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}container{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+ {
+ "colorMode": "critical",
+ "fill": true,
+ "line": true,
+ "op": "gt",
+ "value": 0.25,
+ "yaxis": "left"
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Throttling",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": 1,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU Throttling",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 3,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "CPU Usage",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Requests",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Requests %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "CPU Limits",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Limits %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Container",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "container",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Quota",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU Quota",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 4,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "requests",
+ "color": "#F2495C",
+ "dashes": true,
+ "fill": 0,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ },
+ {
+ "alias": "limits",
+ "color": "#FF9830",
+ "dashes": true,
+ "fill": 0,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ }
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", image!=\"\"}) by (container)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}container{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", resource=\"memory\"}\n)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "requests",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", resource=\"memory\"}\n)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "limits",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Usage (WSS)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 5,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Memory Usage (WSS)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Requests",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Requests %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Memory Limits",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Limits %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Memory Usage (RSS)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Usage (Cache)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #G",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Usage (Swap)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #H",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Container",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "container",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", image!=\"\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", image!=\"\"}) by (container) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", image!=\"\"}) by (container) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_rss{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container != \"\", container != \"POD\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_cache{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container != \"\", container != \"POD\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "G",
+ "step": 10
+ },
+ {
+ "expr": "sum(container_memory_swap{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container != \"\", container != \"POD\"}) by (container)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "H",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Quota",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory Quota",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 6,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Receive Bandwidth",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 7,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Transmit Bandwidth",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Bandwidth",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 8,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 9,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Rate of Packets",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 10,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets Dropped",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 11,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets Dropped",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Rate of Packets Dropped",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "decimals": -1,
+ "fill": 10,
+ "id": 12,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "ceil(sum by(pod) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Reads",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "ceil(sum by(pod) (rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\",namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Writes",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "IOPS",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 13,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum by(pod) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Reads",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "sum by(pod) (rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Writes",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "ThroughPut",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Storage IO - Distribution(Pod - Read & Writes)",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "decimals": -1,
+ "fill": 10,
+ "id": 14,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "ceil(sum by(container) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval])))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}container{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "IOPS(Reads+Writes)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 15,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum by(container) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}container{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "ThroughPut(Read+Write)",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Storage IO - Distribution(Containers)",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 16,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "sort": {
+ "col": 4,
+ "desc": true
+ },
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "IOPS(Reads)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": -1,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "IOPS(Writes)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": -1,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "IOPS(Reads + Writes)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": -1,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Throughput(Read)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Throughput(Write)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Throughput(Read + Write)",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Container",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "container",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum by(container) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum by(container) (rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\",device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum by(container) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum by(container) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum by(container) (rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum by(container) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Storage IO",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Storage IO - Distribution",
+ "titleSize": "h6"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kube-state-metrics\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "namespace",
+ "options": [
+
+ ],
+ "query": "label_values(kube_namespace_status_phase{job=\"kube-state-metrics\", cluster=\"$cluster\"}, namespace)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "pod",
+ "options": [
+
+ ],
+ "query": "label_values(kube_pod_info{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\"}, pod)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Compute Resources / Pod",
+ "uid": "6581e46e4e5c7ba40a07646395ef7b23",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-workload.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-workload.yaml
new file mode 100644
index 00000000..2a30eac7
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-workload.yaml
@@ -0,0 +1,2024 @@
+{{- /*
+Generated from 'k8s-resources-workload' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-workload" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ k8s-resources-workload.json: |-
+ {
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "links": [
+
+ ],
+ "refresh": "10s",
+ "rows": [
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 1,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 2,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "CPU Usage",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Requests",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Requests %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "CPU Limits",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Limits %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Pod",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "/d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell",
+ "pattern": "pod",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n/sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n/sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Quota",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU Quota",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 3,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(\n container_memory_working_set_bytes{cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 4,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Memory Usage",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Requests",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Requests %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Memory Limits",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Limits %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Pod",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "/d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell",
+ "pattern": "pod",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(\n container_memory_working_set_bytes{cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n container_memory_working_set_bytes{cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n/sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n container_memory_working_set_bytes{cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n/sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Quota",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory Quota",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 5,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Current Receive Bandwidth",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Current Transmit Bandwidth",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Rate of Received Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Received Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Pod",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "/d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell",
+ "pattern": "pod",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "(sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "(sum(irate(container_network_receive_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "(sum(irate(container_network_transmit_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "(sum(irate(container_network_receive_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "(sum(irate(container_network_transmit_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Network Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Current Network Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 6,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Receive Bandwidth",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 7,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Transmit Bandwidth",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Bandwidth",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 8,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(avg(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Container Bandwidth by Pod: Received",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 9,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(avg(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Container Bandwidth by Pod: Transmitted",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Average Container Bandwidth by Pod",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 10,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_receive_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 11,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_transmit_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Rate of Packets",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 12,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_receive_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets Dropped",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 13,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_transmit_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets Dropped",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Rate of Packets Dropped",
+ "titleSize": "h6"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kube-state-metrics\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "namespace",
+ "options": [
+
+ ],
+ "query": "label_values(kube_namespace_status_phase{job=\"kube-state-metrics\", cluster=\"$cluster\"}, namespace)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "type",
+ "options": [
+
+ ],
+ "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\"}, workload_type)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "workload",
+ "options": [
+
+ ],
+ "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}, workload)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Compute Resources / Workload",
+ "uid": "a164a7f0339f99e89cea5cb47e9be617",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-workloads-namespace.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-workloads-namespace.yaml
new file mode 100644
index 00000000..13559657
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-workloads-namespace.yaml
@@ -0,0 +1,2189 @@
+{{- /*
+Generated from 'k8s-resources-workloads-namespace' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-workloads-namespace" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ k8s-resources-workloads-namespace.json: |-
+ {
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "links": [
+
+ ],
+ "refresh": "10s",
+ "rows": [
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 1,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "quota - requests",
+ "color": "#F2495C",
+ "dashes": true,
+ "fill": 0,
+ "hiddenSeries": true,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ },
+ {
+ "alias": "quota - limits",
+ "color": "#FF9830",
+ "dashes": true,
+ "fill": 0,
+ "hiddenSeries": true,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ }
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}workload{{`}}`}} - {{`{{`}}workload_type{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"requests.cpu\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "quota - requests",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"limits.cpu\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "quota - limits",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 2,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Running Pods",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 0,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Usage",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Requests",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Requests %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "CPU Limits",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "CPU Limits %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Workload",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "/d/a164a7f0339f99e89cea5cb47e9be617/k8s-resources-workload?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-workload=$__cell&var-type=$__cell_2",
+ "pattern": "workload",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Workload Type",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "workload_type",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "count(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload, workload_type)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n/sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n/sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Quota",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU Quota",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 3,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+ {
+ "alias": "quota - requests",
+ "color": "#F2495C",
+ "dashes": true,
+ "fill": 0,
+ "hiddenSeries": true,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ },
+ {
+ "alias": "quota - limits",
+ "color": "#FF9830",
+ "dashes": true,
+ "fill": 0,
+ "hiddenSeries": true,
+ "hideTooltip": true,
+ "legend": true,
+ "linewidth": 2,
+ "stack": false
+ }
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(\n container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}workload{{`}}`}} - {{`{{`}}workload_type{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"requests.memory\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "quota - requests",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"limits.memory\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "quota - limits",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 4,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Running Pods",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 0,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Memory Usage",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Requests",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Requests %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Memory Limits",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "bytes"
+ },
+ {
+ "alias": "Memory Limits %",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "percentunit"
+ },
+ {
+ "alias": "Workload",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "/d/a164a7f0339f99e89cea5cb47e9be617/k8s-resources-workload?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-workload=$__cell&var-type=$__cell_2",
+ "pattern": "workload",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Workload Type",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "workload_type",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "count(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload, workload_type)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n/sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum(\n container_memory_working_set_bytes{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n/sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Quota",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory Quota",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 5,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Current Receive Bandwidth",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Current Transmit Bandwidth",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Rate of Received Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Received Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Workload",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down to pods",
+ "linkUrl": "/d/a164a7f0339f99e89cea5cb47e9be617/k8s-resources-workload?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-workload=$__cell&var-type=$type",
+ "pattern": "workload",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Workload Type",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "workload_type",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "(sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "(sum(irate(container_network_receive_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "(sum(irate(container_network_transmit_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "(sum(irate(container_network_receive_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "(sum(irate(container_network_transmit_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Network Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Current Network Usage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 6,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Receive Bandwidth",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 7,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Transmit Bandwidth",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Bandwidth",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 8,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(avg(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Container Bandwidth by Workload: Received",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 9,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(avg(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Container Bandwidth by Workload: Transmitted",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Average Container Bandwidth by Workload",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 10,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_receive_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 11,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_transmit_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Rate of Packets",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 12,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_receive_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets Dropped",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 13,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(sum(irate(container_network_transmit_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets Dropped",
+ "tooltip": {
+ "shared": false,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Rate of Packets Dropped",
+ "titleSize": "h6"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kube-state-metrics\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "namespace",
+ "options": [
+
+ ],
+ "query": "label_values(kube_pod_info{job=\"kube-state-metrics\", cluster=\"$cluster\"}, namespace)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "deployment",
+ "value": "deployment"
+ },
+ "datasource": "$datasource",
+ "definition": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\"}, workload_type)",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "type",
+ "options": [
+
+ ],
+ "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\"}, workload_type)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Compute Resources / Namespace (Workloads)",
+ "uid": "a87fb0d919ec0ea5f6543124e16c42a5",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/kubelet.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/kubelet.yaml
new file mode 100644
index 00000000..6335d523
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/kubelet.yaml
@@ -0,0 +1,2254 @@
+{{- /*
+Generated from 'kubelet' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.kubelet.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "kubelet" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ kubelet.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": false,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "panels": [
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "links": [
+
+ ],
+ "mappings": [
+
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+
+ ]
+ },
+ "unit": "none"
+ }
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 4,
+ "x": 0,
+ "y": 0
+ },
+ "id": 2,
+ "links": [
+
+ ],
+ "options": {
+ "colorMode": "value",
+ "graphMode": "area",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "textMode": "auto"
+ },
+ "pluginVersion": "7",
+ "targets": [
+ {
+ "expr": "sum(kubelet_node_name{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "title": "Running Kubelets",
+ "transparent": false,
+ "type": "stat"
+ },
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "links": [
+
+ ],
+ "mappings": [
+
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+
+ ]
+ },
+ "unit": "none"
+ }
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 4,
+ "x": 4,
+ "y": 0
+ },
+ "id": 3,
+ "links": [
+
+ ],
+ "options": {
+ "colorMode": "value",
+ "graphMode": "area",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "textMode": "auto"
+ },
+ "pluginVersion": "7",
+ "targets": [
+ {
+ "expr": "sum(kubelet_running_pods{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\"}) OR sum(kubelet_running_pod_count{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Running Pods",
+ "transparent": false,
+ "type": "stat"
+ },
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "links": [
+
+ ],
+ "mappings": [
+
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+
+ ]
+ },
+ "unit": "none"
+ }
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 4,
+ "x": 8,
+ "y": 0
+ },
+ "id": 4,
+ "links": [
+
+ ],
+ "options": {
+ "colorMode": "value",
+ "graphMode": "area",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "textMode": "auto"
+ },
+ "pluginVersion": "7",
+ "targets": [
+ {
+ "expr": "sum(kubelet_running_containers{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\"}) OR sum(kubelet_running_container_count{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Running Containers",
+ "transparent": false,
+ "type": "stat"
+ },
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "links": [
+
+ ],
+ "mappings": [
+
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+
+ ]
+ },
+ "unit": "none"
+ }
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 4,
+ "x": 12,
+ "y": 0
+ },
+ "id": 5,
+ "links": [
+
+ ],
+ "options": {
+ "colorMode": "value",
+ "graphMode": "area",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "textMode": "auto"
+ },
+ "pluginVersion": "7",
+ "targets": [
+ {
+ "expr": "sum(volume_manager_total_volumes{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\", state=\"actual_state_of_world\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Actual Volume Count",
+ "transparent": false,
+ "type": "stat"
+ },
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "links": [
+
+ ],
+ "mappings": [
+
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+
+ ]
+ },
+ "unit": "none"
+ }
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 4,
+ "x": 16,
+ "y": 0
+ },
+ "id": 6,
+ "links": [
+
+ ],
+ "options": {
+ "colorMode": "value",
+ "graphMode": "area",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "textMode": "auto"
+ },
+ "pluginVersion": "7",
+ "targets": [
+ {
+ "expr": "sum(volume_manager_total_volumes{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\",state=\"desired_state_of_world\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Desired Volume Count",
+ "transparent": false,
+ "type": "stat"
+ },
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "links": [
+
+ ],
+ "mappings": [
+
+ ],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+
+ ]
+ },
+ "unit": "none"
+ }
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 4,
+ "x": 20,
+ "y": 0
+ },
+ "id": 7,
+ "links": [
+
+ ],
+ "options": {
+ "colorMode": "value",
+ "graphMode": "area",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "textMode": "auto"
+ },
+ "pluginVersion": "7",
+ "targets": [
+ {
+ "expr": "sum(rate(kubelet_node_config_error{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "title": "Config Error Count",
+ "transparent": false,
+ "type": "stat"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 0,
+ "y": 7
+ },
+ "id": 8,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(kubelet_runtime_operations_total{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (operation_type, instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_type{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Operation Rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 12,
+ "y": 7
+ },
+ "id": 9,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(kubelet_runtime_operations_errors_total{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_type)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_type{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Operation Error Rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 24,
+ "x": 0,
+ "y": 14
+ },
+ "id": 10,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(kubelet_runtime_operations_duration_seconds_bucket{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_type, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_type{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Operation duration 99th quantile",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 0,
+ "y": 21
+ },
+ "id": 11,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(kubelet_pod_start_duration_seconds_count{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} pod",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(rate(kubelet_pod_worker_duration_seconds_count{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} worker",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Pod Start Rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 12,
+ "y": 21
+ },
+ "id": 12,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(kubelet_pod_start_duration_seconds_bucket{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} pod",
+ "refId": "A"
+ },
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(kubelet_pod_worker_duration_seconds_bucket{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} worker",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Pod Start Duration",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 0,
+ "y": 28
+ },
+ "id": 13,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(storage_operation_duration_seconds_count{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_name, volume_plugin)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_name{{`}}`}} {{`{{`}}volume_plugin{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Storage Operation Rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 12,
+ "y": 28
+ },
+ "id": 14,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(storage_operation_errors_total{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_name, volume_plugin)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_name{{`}}`}} {{`{{`}}volume_plugin{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Storage Operation Error Rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 24,
+ "x": 0,
+ "y": 35
+ },
+ "id": 15,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(storage_operation_duration_seconds_bucket{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_name, volume_plugin, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_name{{`}}`}} {{`{{`}}volume_plugin{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Storage Operation Duration 99th quantile",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 0,
+ "y": 42
+ },
+ "id": 16,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(kubelet_cgroup_manager_duration_seconds_count{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_type)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}operation_type{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Cgroup manager operation rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 12,
+ "y": 42
+ },
+ "id": 17,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(kubelet_cgroup_manager_duration_seconds_bucket{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_type, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_type{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Cgroup manager 99th quantile",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "Pod lifecycle event generator",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 0,
+ "y": 49
+ },
+ "id": 18,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(kubelet_pleg_relist_duration_seconds_count{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\"}[$__rate_interval])) by (instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "PLEG relist rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 12,
+ "x": 12,
+ "y": 49
+ },
+ "id": 19,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(kubelet_pleg_relist_interval_seconds_bucket{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "PLEG relist interval",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 24,
+ "x": 0,
+ "y": 56
+ },
+ "id": 20,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(kubelet_pleg_relist_duration_seconds_bucket{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "PLEG relist duration",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 24,
+ "x": 0,
+ "y": 63
+ },
+ "id": 21,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\",code=~\"2..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "2xx",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\",code=~\"3..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "3xx",
+ "refId": "B"
+ },
+ {
+ "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\",code=~\"4..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "4xx",
+ "refId": "C"
+ },
+ {
+ "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\",code=~\"5..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "5xx",
+ "refId": "D"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "RPC Rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 24,
+ "x": 0,
+ "y": 70
+ },
+ "id": 22,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\", instance=~\"$instance\"}[$__rate_interval])) by (instance, verb, url, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Request duration 99th quantile",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 0,
+ "y": 77
+ },
+ "id": 23,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "process_resident_memory_bytes{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 8,
+ "y": 77
+ },
+ "id": 24,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(process_cpu_seconds_total{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU usage",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 7,
+ "w": 8,
+ "x": 16,
+ "y": 77
+ },
+ "id": 25,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "go_goroutines{cluster=\"$cluster\",job=\"kubelet\", metrics_path=\"/metrics\",instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Goroutines",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "refresh": "10s",
+ "rows": [
+
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": "cluster",
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kubelet\", metrics_path=\"/metrics\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": true,
+ "label": "instance",
+ "multi": false,
+ "name": "instance",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kubelet\", metrics_path=\"/metrics\",cluster=\"$cluster\"}, instance)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Kubelet",
+ "uid": "3138fa155d5915769fbded898ac09fd9",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/namespace-by-pod.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/namespace-by-pod.yaml
new file mode 100644
index 00000000..1e8e61b2
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/namespace-by-pod.yaml
@@ -0,0 +1,1464 @@
+{{- /*
+Generated from 'namespace-by-pod' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "namespace-by-pod" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ namespace-by-pod.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "panels": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 2,
+ "panels": [
+
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Current Bandwidth",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "$datasource",
+ "decimals": 0,
+ "format": "time_series",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 1
+ },
+ "height": 9,
+ "id": 3,
+ "interval": null,
+ "links": [
+
+ ],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "options": {
+ "fieldOptions": {
+ "calcs": [
+ "last"
+ ],
+ "defaults": {
+ "max": 10000000000,
+ "min": 0,
+ "title": "$namespace",
+ "unit": "Bps"
+ },
+ "mappings": [
+
+ ],
+ "override": {
+
+ },
+ "thresholds": [
+ {
+ "color": "dark-green",
+ "index": 0,
+ "value": null
+ },
+ {
+ "color": "dark-yellow",
+ "index": 1,
+ "value": 5000000000
+ },
+ {
+ "color": "dark-red",
+ "index": 2,
+ "value": 7000000000
+ }
+ ],
+ "values": false
+ }
+ },
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 12,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution]))",
+ "format": "time_series",
+ "instant": null,
+ "intervalFactor": 1,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Rate of Bytes Received",
+ "type": "gauge",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "$datasource",
+ "decimals": 0,
+ "format": "time_series",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 1
+ },
+ "height": 9,
+ "id": 4,
+ "interval": null,
+ "links": [
+
+ ],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "options": {
+ "fieldOptions": {
+ "calcs": [
+ "last"
+ ],
+ "defaults": {
+ "max": 10000000000,
+ "min": 0,
+ "title": "$namespace",
+ "unit": "Bps"
+ },
+ "mappings": [
+
+ ],
+ "override": {
+
+ },
+ "thresholds": [
+ {
+ "color": "dark-green",
+ "index": 0,
+ "value": null
+ },
+ {
+ "color": "dark-yellow",
+ "index": 1,
+ "value": 5000000000
+ },
+ {
+ "color": "dark-red",
+ "index": 2,
+ "value": 7000000000
+ }
+ ],
+ "values": false
+ }
+ },
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 12,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution]))",
+ "format": "time_series",
+ "instant": null,
+ "intervalFactor": 1,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Rate of Bytes Transmitted",
+ "type": "gauge",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "columns": [
+ {
+ "text": "Time",
+ "value": "Time"
+ },
+ {
+ "text": "Value #A",
+ "value": "Value #A"
+ },
+ {
+ "text": "Value #B",
+ "value": "Value #B"
+ },
+ {
+ "text": "Value #C",
+ "value": "Value #C"
+ },
+ {
+ "text": "Value #D",
+ "value": "Value #D"
+ },
+ {
+ "text": "Value #E",
+ "value": "Value #E"
+ },
+ {
+ "text": "Value #F",
+ "value": "Value #F"
+ },
+ {
+ "text": "pod",
+ "value": "pod"
+ }
+ ],
+ "datasource": "$datasource",
+ "fill": 1,
+ "fontSize": "100%",
+ "gridPos": {
+ "h": 9,
+ "w": 24,
+ "x": 0,
+ "y": 10
+ },
+ "id": 5,
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null as zero",
+ "renderer": "flot",
+ "scroll": true,
+ "showHeader": true,
+ "sort": {
+ "col": 0,
+ "desc": false
+ },
+ "spaceLength": 10,
+ "span": 24,
+ "styles": [
+ {
+ "alias": "Time",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Time",
+ "thresholds": [
+
+ ],
+ "type": "hidden",
+ "unit": "short"
+ },
+ {
+ "alias": "Bandwidth Received",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Bandwidth Transmitted",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Rate of Received Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Received Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Pod",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTooltip": "Drill down",
+ "linkUrl": "d/7a18067ce943a40ae25454675c19ff5c/kubernetes-networking-pod?orgId=1&refresh=30s&var-namespace=$namespace&var-pod=$__cell",
+ "pattern": "pod",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Status",
+ "type": "table"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 19
+ },
+ "id": 6,
+ "panels": [
+
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Bandwidth",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 20
+ },
+ "id": 7,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Receive Bandwidth",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 20
+ },
+ "id": 8,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Transmit Bandwidth",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 29
+ },
+ "id": 9,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 10,
+ "w": 12,
+ "x": 0,
+ "y": 30
+ },
+ "id": 10,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 10,
+ "w": 12,
+ "x": 12,
+ "y": 30
+ },
+ "id": 11,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Packets",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 30
+ },
+ "id": 12,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 10,
+ "w": 12,
+ "x": 0,
+ "y": 40
+ },
+ "id": 13,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets Dropped",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 10,
+ "w": 12,
+ "x": 12,
+ "y": 40
+ },
+ "id": 14,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets Dropped",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Errors",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "refresh": "10s",
+ "rows": [
+
+ ],
+ "schemaVersion": 18,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": ".+",
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "kube-system",
+ "value": "kube-system"
+ },
+ "datasource": "$datasource",
+ "definition": "label_values(container_network_receive_packets_total{cluster=\"$cluster\"}, namespace)",
+ "hide": 0,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "namespace",
+ "options": [
+
+ ],
+ "query": "label_values(container_network_receive_packets_total{cluster=\"$cluster\"}, namespace)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "5m",
+ "value": "5m"
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "resolution",
+ "options": [
+ {
+ "selected": false,
+ "text": "30s",
+ "value": "30s"
+ },
+ {
+ "selected": true,
+ "text": "5m",
+ "value": "5m"
+ },
+ {
+ "selected": false,
+ "text": "1h",
+ "value": "1h"
+ }
+ ],
+ "query": "30s,5m,1h",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "interval",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "5m",
+ "value": "5m"
+ },
+ "datasource": "$datasource",
+ "hide": 2,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "interval",
+ "options": [
+ {
+ "selected": true,
+ "text": "4h",
+ "value": "4h"
+ }
+ ],
+ "query": "4h",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "interval",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Networking / Namespace (Pods)",
+ "uid": "8b7a8b326d7a6f1f04244066368c67af",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/namespace-by-workload.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/namespace-by-workload.yaml
new file mode 100644
index 00000000..c4fc4bb2
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/namespace-by-workload.yaml
@@ -0,0 +1,1736 @@
+{{- /*
+Generated from 'namespace-by-workload' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "namespace-by-workload" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ namespace-by-workload.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "panels": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 2,
+ "panels": [
+
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Current Bandwidth",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": true,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 1
+ },
+ "id": 3,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": false,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}} workload {{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Rate of Bytes Received",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "series",
+ "name": null,
+ "show": false,
+ "values": [
+ "current"
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": true,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 1
+ },
+ "id": 4,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": false,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}} workload {{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Rate of Bytes Transmitted",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "series",
+ "name": null,
+ "show": false,
+ "values": [
+ "current"
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "columns": [
+ {
+ "text": "Time",
+ "value": "Time"
+ },
+ {
+ "text": "Value #A",
+ "value": "Value #A"
+ },
+ {
+ "text": "Value #B",
+ "value": "Value #B"
+ },
+ {
+ "text": "Value #C",
+ "value": "Value #C"
+ },
+ {
+ "text": "Value #D",
+ "value": "Value #D"
+ },
+ {
+ "text": "Value #E",
+ "value": "Value #E"
+ },
+ {
+ "text": "Value #F",
+ "value": "Value #F"
+ },
+ {
+ "text": "Value #G",
+ "value": "Value #G"
+ },
+ {
+ "text": "Value #H",
+ "value": "Value #H"
+ },
+ {
+ "text": "workload",
+ "value": "workload"
+ }
+ ],
+ "datasource": "$datasource",
+ "fill": 1,
+ "fontSize": "90%",
+ "gridPos": {
+ "h": 9,
+ "w": 24,
+ "x": 0,
+ "y": 10
+ },
+ "id": 5,
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null as zero",
+ "renderer": "flot",
+ "scroll": true,
+ "showHeader": true,
+ "sort": {
+ "col": 0,
+ "desc": false
+ },
+ "spaceLength": 10,
+ "span": 24,
+ "styles": [
+ {
+ "alias": "Time",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Time",
+ "thresholds": [
+
+ ],
+ "type": "hidden",
+ "unit": "short"
+ },
+ {
+ "alias": "Current Bandwidth Received",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Current Bandwidth Transmitted",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Average Bandwidth Received",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #C",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Average Bandwidth Transmitted",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #D",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "Bps"
+ },
+ {
+ "alias": "Rate of Received Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #E",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #F",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Received Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #G",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Rate of Transmitted Packets Dropped",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #H",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "pps"
+ },
+ {
+ "alias": "Workload",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": true,
+ "linkTooltip": "Drill down",
+ "linkUrl": "d/728bf77cc1166d2f3133bf25846876cc/kubernetes-networking-workload?orgId=1&refresh=30s&var-namespace=$namespace&var-type=$type&var-workload=$__cell",
+ "pattern": "workload",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(avg(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "C",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(avg(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "D",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "E",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "F",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "G",
+ "step": 10
+ },
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "H",
+ "step": 10
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Status",
+ "type": "table"
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 19
+ },
+ "id": 6,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": true,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 20
+ },
+ "id": 7,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": false,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(avg(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}} workload {{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Rate of Bytes Received",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "series",
+ "name": null,
+ "show": false,
+ "values": [
+ "current"
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": true,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 20
+ },
+ "id": 8,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": false,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(avg(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}} workload {{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Rate of Bytes Transmitted",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "series",
+ "name": null,
+ "show": false,
+ "values": [
+ "current"
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Average Bandwidth",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 29
+ },
+ "id": 9,
+ "panels": [
+
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Bandwidth HIstory",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 38
+ },
+ "id": 10,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Receive Bandwidth",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 38
+ },
+ "id": 11,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Transmit Bandwidth",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 39
+ },
+ "id": 12,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 40
+ },
+ "id": 13,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 40
+ },
+ "id": 14,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Packets",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 40
+ },
+ "id": 15,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 41
+ },
+ "id": 16,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets Dropped",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 41
+ },
+ "id": 17,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}workload{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets Dropped",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Errors",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "refresh": "10s",
+ "rows": [
+
+ ],
+ "schemaVersion": 18,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "kube-system",
+ "value": "kube-system"
+ },
+ "datasource": "$datasource",
+ "definition": "label_values(container_network_receive_packets_total{cluster=\"$cluster\"}, namespace)",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "namespace",
+ "options": [
+
+ ],
+ "query": "label_values(container_network_receive_packets_total{cluster=\"$cluster\"}, namespace)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "deployment",
+ "value": "deployment"
+ },
+ "datasource": "$datasource",
+ "definition": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\"}, workload_type)",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "type",
+ "options": [
+
+ ],
+ "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\"}, workload_type)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "5m",
+ "value": "5m"
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "resolution",
+ "options": [
+ {
+ "selected": false,
+ "text": "30s",
+ "value": "30s"
+ },
+ {
+ "selected": true,
+ "text": "5m",
+ "value": "5m"
+ },
+ {
+ "selected": false,
+ "text": "1h",
+ "value": "1h"
+ }
+ ],
+ "query": "30s,5m,1h",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "interval",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "5m",
+ "value": "5m"
+ },
+ "datasource": "$datasource",
+ "hide": 2,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "interval",
+ "options": [
+ {
+ "selected": true,
+ "text": "4h",
+ "value": "4h"
+ }
+ ],
+ "query": "4h",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "interval",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Networking / Namespace (Workload)",
+ "uid": "bbb2a765a623ae38130206c7d94a160f",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/node-cluster-rsrc-use.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/node-cluster-rsrc-use.yaml
new file mode 100644
index 00000000..a0bdbb75
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/node-cluster-rsrc-use.yaml
@@ -0,0 +1,1063 @@
+{{- /*
+Generated from 'node-cluster-rsrc-use' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.nodeExporter.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "node-cluster-rsrc-use" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ node-cluster-rsrc-use.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": false,
+ "gnetId": null,
+ "graphTooltip": 1,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "refresh": "30s",
+ "rows": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 2,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "((\n instance:node_cpu_utilisation:rate5m{job=\"node-exporter\", cluster=\"$cluster\"}\n *\n instance:node_num_cpu:sum{job=\"node-exporter\", cluster=\"$cluster\"}\n) != 0 )\n/ scalar(sum(instance:node_num_cpu:sum{job=\"node-exporter\", cluster=\"$cluster\"}))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}} instance {{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Utilisation",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 3,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(\n instance:node_load1_per_cpu:ratio{job=\"node-exporter\", cluster=\"$cluster\"}\n / scalar(count(instance:node_load1_per_cpu:ratio{job=\"node-exporter\", cluster=\"$cluster\"}))\n) != 0\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Saturation (Load1 per CPU)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 4,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(\n instance:node_memory_utilisation:ratio{job=\"node-exporter\", cluster=\"$cluster\"}\n / scalar(count(instance:node_memory_utilisation:ratio{job=\"node-exporter\", cluster=\"$cluster\"}))\n) != 0\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Utilisation",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 5,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "instance:node_vmstat_pgmajfault:rate5m{job=\"node-exporter\", cluster=\"$cluster\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Saturation (Major Page Faults)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "rds",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "rds",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 6,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+ {
+ "alias": "/Receive/",
+ "stack": "A"
+ },
+ {
+ "alias": "/Transmit/",
+ "stack": "B",
+ "transform": "negative-Y"
+ }
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "instance:node_network_receive_bytes_excluding_lo:rate5m{job=\"node-exporter\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Receive",
+ "refId": "A"
+ },
+ {
+ "expr": "instance:node_network_transmit_bytes_excluding_lo:rate5m{job=\"node-exporter\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Transmit",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Network Utilisation (Bytes Receive/Transmit)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 7,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+ {
+ "alias": "/ Receive/",
+ "stack": "A"
+ },
+ {
+ "alias": "/ Transmit/",
+ "stack": "B",
+ "transform": "negative-Y"
+ }
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "instance:node_network_receive_drop_excluding_lo:rate5m{job=\"node-exporter\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Receive",
+ "refId": "A"
+ },
+ {
+ "expr": "instance:node_network_transmit_drop_excluding_lo:rate5m{job=\"node-exporter\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} Transmit",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Network Saturation (Drops Receive/Transmit)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Network",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 8,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(\n instance_device:node_disk_io_time_seconds:rate5m{job=\"node-exporter\", cluster=\"$cluster\"}\n / scalar(count(instance_device:node_disk_io_time_seconds:rate5m{job=\"node-exporter\", cluster=\"$cluster\"}))\n) != 0\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}device{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Disk IO Utilisation",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 9,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(\n instance_device:node_disk_io_time_weighted_seconds:rate5m{job=\"node-exporter\", cluster=\"$cluster\"}\n / scalar(count(instance_device:node_disk_io_time_weighted_seconds:rate5m{job=\"node-exporter\", cluster=\"$cluster\"}))\n) != 0\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}device{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Disk IO Saturation",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Disk IO",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 10,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum without (device) (\n max without (fstype, mountpoint) ((\n node_filesystem_size_bytes{job=\"node-exporter\", fstype!=\"\", cluster=\"$cluster\"}\n -\n node_filesystem_avail_bytes{job=\"node-exporter\", fstype!=\"\", cluster=\"$cluster\"}\n ) != 0)\n)\n/ scalar(sum(max without (fstype, mountpoint) (node_filesystem_size_bytes{job=\"node-exporter\", fstype!=\"\", cluster=\"$cluster\"})))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Disk Space Utilisation",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Disk Space",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "node-exporter-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(node_time_seconds, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Node Exporter / USE Method / Cluster",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/node-rsrc-use.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/node-rsrc-use.yaml
new file mode 100644
index 00000000..6ed320d0
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/node-rsrc-use.yaml
@@ -0,0 +1,1089 @@
+{{- /*
+Generated from 'node-rsrc-use' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.nodeExporter.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "node-rsrc-use" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ node-rsrc-use.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": false,
+ "gnetId": null,
+ "graphTooltip": 1,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "refresh": "30s",
+ "rows": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 2,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "instance:node_cpu_utilisation:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Utilisation",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Utilisation",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 3,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "instance:node_load1_per_cpu:ratio{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Saturation",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Saturation (Load1 per CPU)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 4,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "instance:node_memory_utilisation:ratio{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Utilisation",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Utilisation",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 5,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "instance:node_vmstat_pgmajfault:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Major page Faults",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Saturation (Major Page Faults)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "rds",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "rds",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 6,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+ {
+ "alias": "/Receive/",
+ "stack": "A"
+ },
+ {
+ "alias": "/Transmit/",
+ "stack": "B",
+ "transform": "negative-Y"
+ }
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "instance:node_network_receive_bytes_excluding_lo:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Receive",
+ "refId": "A"
+ },
+ {
+ "expr": "instance:node_network_transmit_bytes_excluding_lo:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Transmit",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Network Utilisation (Bytes Receive/Transmit)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 7,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+ {
+ "alias": "/ Receive/",
+ "stack": "A"
+ },
+ {
+ "alias": "/ Transmit/",
+ "stack": "B",
+ "transform": "negative-Y"
+ }
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "instance:node_network_receive_drop_excluding_lo:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Receive",
+ "refId": "A"
+ },
+ {
+ "expr": "instance:node_network_transmit_drop_excluding_lo:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Transmit",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Network Saturation (Drops Receive/Transmit)",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Network",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 8,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "instance_device:node_disk_io_time_seconds:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}device{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Disk IO Utilisation",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 9,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "instance_device:node_disk_io_time_weighted_seconds:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}device{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Disk IO Saturation",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Disk IO",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 10,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": false,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(1 -\n (\n max without (mountpoint, fstype) (node_filesystem_avail_bytes{job=\"node-exporter\", fstype!=\"\", instance=\"$instance\", cluster=\"$cluster\"})\n /\n max without (mountpoint, fstype) (node_filesystem_size_bytes{job=\"node-exporter\", fstype!=\"\", instance=\"$instance\", cluster=\"$cluster\"})\n ) != 0\n)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}device{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Disk Space Utilisation",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Disk Space",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "node-exporter-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(node_time_seconds, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "instance",
+ "options": [
+
+ ],
+ "query": "label_values(node_exporter_build_info{job=\"node-exporter\", cluster=\"$cluster\"}, instance)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Node Exporter / USE Method / Node",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/nodes-darwin.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/nodes-darwin.yaml
new file mode 100644
index 00000000..3a706b84
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/nodes-darwin.yaml
@@ -0,0 +1,1073 @@
+{{- /*
+Generated from 'nodes-darwin' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "nodes-darwin" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ nodes-darwin.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": false,
+ "gnetId": null,
+ "graphTooltip": 1,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "refresh": "30s",
+ "rows": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 2,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(\n (1 - sum without (mode) (rate(node_cpu_seconds_total{job=\"node-exporter\", mode=~\"idle|iowait|steal\", instance=\"$instance\"}[$__rate_interval])))\n/ ignoring(cpu) group_left\n count without (cpu, mode) (node_cpu_seconds_total{job=\"node-exporter\", mode=\"idle\", instance=\"$instance\"})\n)\n",
+ "format": "time_series",
+ "intervalFactor": 5,
+ "legendFormat": "{{`{{`}}cpu{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Usage",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": 1,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": 1,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 0,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 3,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "node_load1{job=\"node-exporter\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "1m load average",
+ "refId": "A"
+ },
+ {
+ "expr": "node_load5{job=\"node-exporter\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "5m load average",
+ "refId": "B"
+ },
+ {
+ "expr": "node_load15{job=\"node-exporter\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "15m load average",
+ "refId": "C"
+ },
+ {
+ "expr": "count(node_cpu_seconds_total{job=\"node-exporter\", instance=\"$instance\", mode=\"idle\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "logical cores",
+ "refId": "D"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Load Average",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 4,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 9,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "node_memory_total_bytes{job=\"node-exporter\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Physical Memory",
+ "refId": "A"
+ },
+ {
+ "expr": "(\n node_memory_internal_bytes{job=\"node-exporter\", instance=\"$instance\"} -\n node_memory_purgeable_bytes{job=\"node-exporter\", instance=\"$instance\"} +\n node_memory_wired_bytes{job=\"node-exporter\", instance=\"$instance\"} +\n node_memory_compressed_bytes{job=\"node-exporter\", instance=\"$instance\"}\n)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Memory Used",
+ "refId": "B"
+ },
+ {
+ "expr": "(\n node_memory_internal_bytes{job=\"node-exporter\", instance=\"$instance\"} -\n node_memory_purgeable_bytes{job=\"node-exporter\", instance=\"$instance\"}\n)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "App Memory",
+ "refId": "C"
+ },
+ {
+ "expr": "node_memory_wired_bytes{job=\"node-exporter\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Wired Memory",
+ "refId": "D"
+ },
+ {
+ "expr": "node_memory_compressed_bytes{job=\"node-exporter\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Compressed",
+ "refId": "E"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Usage",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "max": 100,
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "rgba(50, 172, 45, 0.97)"
+ },
+ {
+ "color": "rgba(237, 129, 40, 0.89)",
+ "value": 80
+ },
+ {
+ "color": "rgba(245, 54, 54, 0.9)",
+ "value": 90
+ }
+ ]
+ },
+ "unit": "percent"
+ }
+ },
+ "gridPos": {
+
+ },
+ "id": 5,
+ "span": 3,
+ "targets": [
+ {
+ "expr": "(\n (\n avg(node_memory_internal_bytes{job=\"node-exporter\", instance=\"$instance\"}) -\n avg(node_memory_purgeable_bytes{job=\"node-exporter\", instance=\"$instance\"}) +\n avg(node_memory_wired_bytes{job=\"node-exporter\", instance=\"$instance\"}) +\n avg(node_memory_compressed_bytes{job=\"node-exporter\", instance=\"$instance\"})\n ) /\n avg(node_memory_total_bytes{job=\"node-exporter\", instance=\"$instance\"})\n)\n*\n100\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": ""
+ }
+ ],
+ "title": "Memory Usage",
+ "transparent": false,
+ "type": "gauge"
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 0,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 6,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+ {
+ "alias": "/ read| written/",
+ "yaxis": 1
+ },
+ {
+ "alias": "/ io time/",
+ "yaxis": 2
+ }
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(node_disk_read_bytes_total{job=\"node-exporter\", instance=\"$instance\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\"}[$__rate_interval])",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}device{{`}}`}} read",
+ "refId": "A"
+ },
+ {
+ "expr": "rate(node_disk_written_bytes_total{job=\"node-exporter\", instance=\"$instance\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\"}[$__rate_interval])",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}device{{`}}`}} written",
+ "refId": "B"
+ },
+ {
+ "expr": "rate(node_disk_io_time_seconds_total{job=\"node-exporter\", instance=\"$instance\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\"}[$__rate_interval])",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}device{{`}}`}} io time",
+ "refId": "C"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Disk I/O",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "custom": {
+
+ },
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ },
+ {
+ "color": "yellow",
+ "value": 0.8
+ },
+ {
+ "color": "red",
+ "value": 0.9
+ }
+ ]
+ },
+ "unit": "decbytes"
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Mounted on"
+ },
+ "properties": [
+ {
+ "id": "custom.width",
+ "value": 260
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Size"
+ },
+ "properties": [
+ {
+ "id": "custom.width",
+ "value": 93
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Used"
+ },
+ "properties": [
+ {
+ "id": "custom.width",
+ "value": 72
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Available"
+ },
+ "properties": [
+ {
+ "id": "custom.width",
+ "value": 88
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Used, %"
+ },
+ "properties": [
+ {
+ "id": "unit",
+ "value": "percentunit"
+ },
+ {
+ "id": "custom.displayMode",
+ "value": "gradient-gauge"
+ },
+ {
+ "id": "max",
+ "value": 1
+ },
+ {
+ "id": "min",
+ "value": 0
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+
+ },
+ "id": 7,
+ "span": 6,
+ "targets": [
+ {
+ "expr": "max by (mountpoint) (node_filesystem_size_bytes{job=\"node-exporter\", instance=\"$instance\", fstype!=\"\"})\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": ""
+ },
+ {
+ "expr": "max by (mountpoint) (node_filesystem_avail_bytes{job=\"node-exporter\", instance=\"$instance\", fstype!=\"\"})\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": ""
+ }
+ ],
+ "title": "Disk Space Usage",
+ "transformations": [
+ {
+ "id": "groupBy",
+ "options": {
+ "fields": {
+ "Value #A": {
+ "aggregations": [
+ "lastNotNull"
+ ],
+ "operation": "aggregate"
+ },
+ "Value #B": {
+ "aggregations": [
+ "lastNotNull"
+ ],
+ "operation": "aggregate"
+ },
+ "mountpoint": {
+ "aggregations": [
+
+ ],
+ "operation": "groupby"
+ }
+ }
+ }
+ },
+ {
+ "id": "merge",
+ "options": {
+
+ }
+ },
+ {
+ "id": "calculateField",
+ "options": {
+ "alias": "Used",
+ "binary": {
+ "left": "Value #A (lastNotNull)",
+ "operator": "-",
+ "reducer": "sum",
+ "right": "Value #B (lastNotNull)"
+ },
+ "mode": "binary",
+ "reduce": {
+ "reducer": "sum"
+ }
+ }
+ },
+ {
+ "id": "calculateField",
+ "options": {
+ "alias": "Used, %",
+ "binary": {
+ "left": "Used",
+ "operator": "/",
+ "reducer": "sum",
+ "right": "Value #A (lastNotNull)"
+ },
+ "mode": "binary",
+ "reduce": {
+ "reducer": "sum"
+ }
+ }
+ },
+ {
+ "id": "organize",
+ "options": {
+ "excludeByName": {
+
+ },
+ "indexByName": {
+
+ },
+ "renameByName": {
+ "Value #A (lastNotNull)": "Size",
+ "Value #B (lastNotNull)": "Available",
+ "mountpoint": "Mounted on"
+ }
+ }
+ },
+ {
+ "id": "sortBy",
+ "options": {
+ "fields": {
+
+ },
+ "sort": [
+ {
+ "field": "Mounted on"
+ }
+ ]
+ }
+ }
+ ],
+ "transparent": false,
+ "type": "table"
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Disk",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "Network received (bits/s)",
+ "fill": 0,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 8,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(node_network_receive_bytes_total{job=\"node-exporter\", instance=\"$instance\", device!=\"lo\"}[$__rate_interval]) * 8",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}device{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Network Received",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "Network transmitted (bits/s)",
+ "fill": 0,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 9,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(node_network_transmit_bytes_total{job=\"node-exporter\", instance=\"$instance\", device!=\"lo\"}[$__rate_interval]) * 8",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}device{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Network Transmitted",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Network",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "node-exporter-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": "Instance",
+ "multi": false,
+ "name": "instance",
+ "options": [
+
+ ],
+ "query": "label_values(node_uname_info{job=\"node-exporter\", sysname=\"Darwin\"}, instance)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Node Exporter / MacOS",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/nodes.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/nodes.yaml
new file mode 100644
index 00000000..d575e048
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/nodes.yaml
@@ -0,0 +1,1066 @@
+{{- /*
+Generated from 'nodes' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.nodeExporter.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "nodes" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ nodes.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": false,
+ "gnetId": null,
+ "graphTooltip": 1,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "refresh": "30s",
+ "rows": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 2,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(\n (1 - sum without (mode) (rate(node_cpu_seconds_total{job=\"node-exporter\", mode=~\"idle|iowait|steal\", instance=\"$instance\"}[$__rate_interval])))\n/ ignoring(cpu) group_left\n count without (cpu, mode) (node_cpu_seconds_total{job=\"node-exporter\", mode=\"idle\", instance=\"$instance\"})\n)\n",
+ "format": "time_series",
+ "intervalFactor": 5,
+ "legendFormat": "{{`{{`}}cpu{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU Usage",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": 1,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": 1,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 0,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 3,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "node_load1{job=\"node-exporter\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "1m load average",
+ "refId": "A"
+ },
+ {
+ "expr": "node_load5{job=\"node-exporter\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "5m load average",
+ "refId": "B"
+ },
+ {
+ "expr": "node_load15{job=\"node-exporter\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "15m load average",
+ "refId": "C"
+ },
+ {
+ "expr": "count(node_cpu_seconds_total{job=\"node-exporter\", instance=\"$instance\", mode=\"idle\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "logical cores",
+ "refId": "D"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Load Average",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "CPU",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 4,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 9,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(\n node_memory_MemTotal_bytes{job=\"node-exporter\", instance=\"$instance\"}\n-\n node_memory_MemFree_bytes{job=\"node-exporter\", instance=\"$instance\"}\n-\n node_memory_Buffers_bytes{job=\"node-exporter\", instance=\"$instance\"}\n-\n node_memory_Cached_bytes{job=\"node-exporter\", instance=\"$instance\"}\n)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "memory used",
+ "refId": "A"
+ },
+ {
+ "expr": "node_memory_Buffers_bytes{job=\"node-exporter\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "memory buffers",
+ "refId": "B"
+ },
+ {
+ "expr": "node_memory_Cached_bytes{job=\"node-exporter\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "memory cached",
+ "refId": "C"
+ },
+ {
+ "expr": "node_memory_MemFree_bytes{job=\"node-exporter\", instance=\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "memory free",
+ "refId": "D"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory Usage",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "max": 100,
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "rgba(50, 172, 45, 0.97)"
+ },
+ {
+ "color": "rgba(237, 129, 40, 0.89)",
+ "value": 80
+ },
+ {
+ "color": "rgba(245, 54, 54, 0.9)",
+ "value": 90
+ }
+ ]
+ },
+ "unit": "percent"
+ }
+ },
+ "gridPos": {
+
+ },
+ "id": 5,
+ "span": 3,
+ "targets": [
+ {
+ "expr": "100 -\n(\n avg(node_memory_MemAvailable_bytes{job=\"node-exporter\", instance=\"$instance\"}) /\n avg(node_memory_MemTotal_bytes{job=\"node-exporter\", instance=\"$instance\"})\n* 100\n)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": ""
+ }
+ ],
+ "title": "Memory Usage",
+ "transparent": false,
+ "type": "gauge"
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Memory",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 0,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 6,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+ {
+ "alias": "/ read| written/",
+ "yaxis": 1
+ },
+ {
+ "alias": "/ io time/",
+ "yaxis": 2
+ }
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(node_disk_read_bytes_total{job=\"node-exporter\", instance=\"$instance\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\"}[$__rate_interval])",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}device{{`}}`}} read",
+ "refId": "A"
+ },
+ {
+ "expr": "rate(node_disk_written_bytes_total{job=\"node-exporter\", instance=\"$instance\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\"}[$__rate_interval])",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}device{{`}}`}} written",
+ "refId": "B"
+ },
+ {
+ "expr": "rate(node_disk_io_time_seconds_total{job=\"node-exporter\", instance=\"$instance\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)\"}[$__rate_interval])",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}device{{`}}`}} io time",
+ "refId": "C"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Disk I/O",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "datasource": "$datasource",
+ "fieldConfig": {
+ "defaults": {
+ "custom": {
+
+ },
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ },
+ {
+ "color": "yellow",
+ "value": 0.8
+ },
+ {
+ "color": "red",
+ "value": 0.9
+ }
+ ]
+ },
+ "unit": "decbytes"
+ },
+ "overrides": [
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Mounted on"
+ },
+ "properties": [
+ {
+ "id": "custom.width",
+ "value": 260
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Size"
+ },
+ "properties": [
+ {
+ "id": "custom.width",
+ "value": 93
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Used"
+ },
+ "properties": [
+ {
+ "id": "custom.width",
+ "value": 72
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Available"
+ },
+ "properties": [
+ {
+ "id": "custom.width",
+ "value": 88
+ }
+ ]
+ },
+ {
+ "matcher": {
+ "id": "byName",
+ "options": "Used, %"
+ },
+ "properties": [
+ {
+ "id": "unit",
+ "value": "percentunit"
+ },
+ {
+ "id": "custom.displayMode",
+ "value": "gradient-gauge"
+ },
+ {
+ "id": "max",
+ "value": 1
+ },
+ {
+ "id": "min",
+ "value": 0
+ }
+ ]
+ }
+ ]
+ },
+ "gridPos": {
+
+ },
+ "id": 7,
+ "span": 6,
+ "targets": [
+ {
+ "expr": "max by (mountpoint) (node_filesystem_size_bytes{job=\"node-exporter\", instance=\"$instance\", fstype!=\"\"})\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": ""
+ },
+ {
+ "expr": "max by (mountpoint) (node_filesystem_avail_bytes{job=\"node-exporter\", instance=\"$instance\", fstype!=\"\"})\n",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": ""
+ }
+ ],
+ "title": "Disk Space Usage",
+ "transformations": [
+ {
+ "id": "groupBy",
+ "options": {
+ "fields": {
+ "Value #A": {
+ "aggregations": [
+ "lastNotNull"
+ ],
+ "operation": "aggregate"
+ },
+ "Value #B": {
+ "aggregations": [
+ "lastNotNull"
+ ],
+ "operation": "aggregate"
+ },
+ "mountpoint": {
+ "aggregations": [
+
+ ],
+ "operation": "groupby"
+ }
+ }
+ }
+ },
+ {
+ "id": "merge",
+ "options": {
+
+ }
+ },
+ {
+ "id": "calculateField",
+ "options": {
+ "alias": "Used",
+ "binary": {
+ "left": "Value #A (lastNotNull)",
+ "operator": "-",
+ "reducer": "sum",
+ "right": "Value #B (lastNotNull)"
+ },
+ "mode": "binary",
+ "reduce": {
+ "reducer": "sum"
+ }
+ }
+ },
+ {
+ "id": "calculateField",
+ "options": {
+ "alias": "Used, %",
+ "binary": {
+ "left": "Used",
+ "operator": "/",
+ "reducer": "sum",
+ "right": "Value #A (lastNotNull)"
+ },
+ "mode": "binary",
+ "reduce": {
+ "reducer": "sum"
+ }
+ }
+ },
+ {
+ "id": "organize",
+ "options": {
+ "excludeByName": {
+
+ },
+ "indexByName": {
+
+ },
+ "renameByName": {
+ "Value #A (lastNotNull)": "Size",
+ "Value #B (lastNotNull)": "Available",
+ "mountpoint": "Mounted on"
+ }
+ }
+ },
+ {
+ "id": "sortBy",
+ "options": {
+ "fields": {
+
+ },
+ "sort": [
+ {
+ "field": "Mounted on"
+ }
+ ]
+ }
+ }
+ ],
+ "transparent": false,
+ "type": "table"
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Disk",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "Network received (bits/s)",
+ "fill": 0,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 8,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(node_network_receive_bytes_total{job=\"node-exporter\", instance=\"$instance\", device!=\"lo\"}[$__rate_interval]) * 8",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}device{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Network Received",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "description": "Network transmitted (bits/s)",
+ "fill": 0,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 9,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(node_network_transmit_bytes_total{job=\"node-exporter\", instance=\"$instance\", device!=\"lo\"}[$__rate_interval]) * 8",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}device{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Network Transmitted",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Network",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "node-exporter-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": "Instance",
+ "multi": false,
+ "name": "instance",
+ "options": [
+
+ ],
+ "query": "label_values(node_uname_info{job=\"node-exporter\", sysname!=\"Darwin\"}, instance)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Node Exporter / Nodes",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/persistentvolumesusage.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/persistentvolumesusage.yaml
new file mode 100644
index 00000000..3fc290dc
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/persistentvolumesusage.yaml
@@ -0,0 +1,587 @@
+{{- /*
+Generated from 'persistentvolumesusage' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "persistentvolumesusage" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ persistentvolumesusage.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": false,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "refresh": "10s",
+ "rows": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 2,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "max": true,
+ "min": true,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 9,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(\n sum without(instance, node) (topk(1, (kubelet_volume_stats_capacity_bytes{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})))\n -\n sum without(instance, node) (topk(1, (kubelet_volume_stats_available_bytes{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})))\n)\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "Used Space",
+ "refId": "A"
+ },
+ {
+ "expr": "sum without(instance, node) (topk(1, (kubelet_volume_stats_available_bytes{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "Free Space",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Volume Space Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "rgba(50, 172, 45, 0.97)",
+ "rgba(237, 129, 40, 0.89)",
+ "rgba(245, 54, 54, 0.9)"
+ ],
+ "datasource": "$datasource",
+ "format": "percent",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": true,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+
+ },
+ "id": 3,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "rightSide": true
+ },
+ "links": [
+
+ ],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 3,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "max without(instance,node) (\n(\n topk(1, kubelet_volume_stats_capacity_bytes{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})\n -\n topk(1, kubelet_volume_stats_available_bytes{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})\n)\n/\ntopk(1, kubelet_volume_stats_capacity_bytes{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})\n* 100)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "80, 90",
+ "title": "Volume Space Usage",
+ "tooltip": {
+ "shared": false
+ },
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 4,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": true,
+ "current": true,
+ "max": true,
+ "min": true,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 9,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum without(instance, node) (topk(1, (kubelet_volume_stats_inodes_used{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "Used inodes",
+ "refId": "A"
+ },
+ {
+ "expr": "(\n sum without(instance, node) (topk(1, (kubelet_volume_stats_inodes{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})))\n -\n sum without(instance, node) (topk(1, (kubelet_volume_stats_inodes_used{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})))\n)\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": " Free inodes",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Volume inodes Usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "none",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "none",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "rgba(50, 172, 45, 0.97)",
+ "rgba(237, 129, 40, 0.89)",
+ "rgba(245, 54, 54, 0.9)"
+ ],
+ "datasource": "$datasource",
+ "format": "percent",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": true,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+
+ },
+ "id": 5,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "rightSide": true
+ },
+ "links": [
+
+ ],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 3,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "max without(instance,node) (\ntopk(1, kubelet_volume_stats_inodes_used{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})\n/\ntopk(1, kubelet_volume_stats_inodes{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})\n* 100)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "80, 90",
+ "title": "Volume inodes Usage",
+ "tooltip": {
+ "shared": false
+ },
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": "cluster",
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(kubelet_volume_stats_capacity_bytes{job=\"kubelet\", metrics_path=\"/metrics\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": "Namespace",
+ "multi": false,
+ "name": "namespace",
+ "options": [
+
+ ],
+ "query": "label_values(kubelet_volume_stats_capacity_bytes{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\"}, namespace)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": "PersistentVolumeClaim",
+ "multi": false,
+ "name": "volume",
+ "options": [
+
+ ],
+ "query": "label_values(kubelet_volume_stats_capacity_bytes{cluster=\"$cluster\", job=\"kubelet\", metrics_path=\"/metrics\", namespace=\"$namespace\"}, persistentvolumeclaim)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-7d",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Persistent Volumes",
+ "uid": "919b92a8e8041bd567af9edab12c840c",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/pod-total.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/pod-total.yaml
new file mode 100644
index 00000000..ff50c49c
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/pod-total.yaml
@@ -0,0 +1,1228 @@
+{{- /*
+Generated from 'pod-total' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "pod-total" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ pod-total.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "panels": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 2,
+ "panels": [
+
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Current Bandwidth",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "$datasource",
+ "decimals": 0,
+ "format": "time_series",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 1
+ },
+ "height": 9,
+ "id": 3,
+ "interval": null,
+ "links": [
+
+ ],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "options": {
+ "fieldOptions": {
+ "calcs": [
+ "last"
+ ],
+ "defaults": {
+ "max": 10000000000,
+ "min": 0,
+ "title": "$namespace: $pod",
+ "unit": "Bps"
+ },
+ "mappings": [
+
+ ],
+ "override": {
+
+ },
+ "thresholds": [
+ {
+ "color": "dark-green",
+ "index": 0,
+ "value": null
+ },
+ {
+ "color": "dark-yellow",
+ "index": 1,
+ "value": 5000000000
+ },
+ {
+ "color": "dark-red",
+ "index": 2,
+ "value": 7000000000
+ }
+ ],
+ "values": false
+ }
+ },
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 12,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution]))",
+ "format": "time_series",
+ "instant": null,
+ "intervalFactor": 1,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Rate of Bytes Received",
+ "type": "gauge",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "$datasource",
+ "decimals": 0,
+ "format": "time_series",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 1
+ },
+ "height": 9,
+ "id": 4,
+ "interval": null,
+ "links": [
+
+ ],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "options": {
+ "fieldOptions": {
+ "calcs": [
+ "last"
+ ],
+ "defaults": {
+ "max": 10000000000,
+ "min": 0,
+ "title": "$namespace: $pod",
+ "unit": "Bps"
+ },
+ "mappings": [
+
+ ],
+ "override": {
+
+ },
+ "thresholds": [
+ {
+ "color": "dark-green",
+ "index": 0,
+ "value": null
+ },
+ {
+ "color": "dark-yellow",
+ "index": 1,
+ "value": 5000000000
+ },
+ {
+ "color": "dark-red",
+ "index": 2,
+ "value": 7000000000
+ }
+ ],
+ "values": false
+ }
+ },
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 12,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution]))",
+ "format": "time_series",
+ "instant": null,
+ "intervalFactor": 1,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Rate of Bytes Transmitted",
+ "type": "gauge",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "current"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 10
+ },
+ "id": 5,
+ "panels": [
+
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Bandwidth",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 11
+ },
+ "id": 6,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Receive Bandwidth",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 11
+ },
+ "id": 7,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Transmit Bandwidth",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 20
+ },
+ "id": 8,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 10,
+ "w": 12,
+ "x": 0,
+ "y": 21
+ },
+ "id": 9,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 10,
+ "w": 12,
+ "x": 12,
+ "y": 21
+ },
+ "id": 10,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Packets",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 21
+ },
+ "id": 11,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 10,
+ "w": 12,
+ "x": 0,
+ "y": 32
+ },
+ "id": 12,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets Dropped",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 10,
+ "w": 12,
+ "x": 12,
+ "y": 32
+ },
+ "id": 13,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution])) by (pod)",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets Dropped",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Errors",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "refresh": "10s",
+ "rows": [
+
+ ],
+ "schemaVersion": 18,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": ".+",
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "kube-system",
+ "value": "kube-system"
+ },
+ "datasource": "$datasource",
+ "definition": "label_values(container_network_receive_packets_total{cluster=\"$cluster\"}, namespace)",
+ "hide": 0,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "namespace",
+ "options": [
+
+ ],
+ "query": "label_values(container_network_receive_packets_total{cluster=\"$cluster\"}, namespace)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": ".+",
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "definition": "label_values(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\"}, pod)",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "pod",
+ "options": [
+
+ ],
+ "query": "label_values(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\"}, pod)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "5m",
+ "value": "5m"
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "resolution",
+ "options": [
+ {
+ "selected": false,
+ "text": "30s",
+ "value": "30s"
+ },
+ {
+ "selected": true,
+ "text": "5m",
+ "value": "5m"
+ },
+ {
+ "selected": false,
+ "text": "1h",
+ "value": "1h"
+ }
+ ],
+ "query": "30s,5m,1h",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "interval",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "5m",
+ "value": "5m"
+ },
+ "datasource": "$datasource",
+ "hide": 2,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "interval",
+ "options": [
+ {
+ "selected": true,
+ "text": "4h",
+ "value": "4h"
+ }
+ ],
+ "query": "4h",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "interval",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Networking / Pod",
+ "uid": "7a18067ce943a40ae25454675c19ff5c",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/prometheus-remote-write.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/prometheus-remote-write.yaml
new file mode 100644
index 00000000..f8ffafc4
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/prometheus-remote-write.yaml
@@ -0,0 +1,1670 @@
+{{- /*
+Generated from 'prometheus-remote-write' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.prometheus.prometheusSpec.remoteWriteDashboards }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "prometheus-remote-write" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ prometheus-remote-write.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "refresh": "60s",
+ "rows": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 2,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "(\n prometheus_remote_storage_highest_timestamp_in_seconds{cluster=~\"$cluster\", instance=~\"$instance\"} \n- \n ignoring(remote_name, url) group_right(instance) (prometheus_remote_storage_queue_highest_sent_timestamp_seconds{cluster=~\"$cluster\", instance=~\"$instance\"} != 0)\n)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Highest Timestamp In vs. Highest Timestamp Sent",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 3,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "clamp_min(\n rate(prometheus_remote_storage_highest_timestamp_in_seconds{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]) \n- \n ignoring (remote_name, url) group_right(instance) rate(prometheus_remote_storage_queue_highest_sent_timestamp_seconds{cluster=~\"$cluster\", instance=~\"$instance\"}[5m])\n, 0)\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate[5m]",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Timestamps",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 4,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(\n prometheus_remote_storage_samples_in_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m])\n- \n ignoring(remote_name, url) group_right(instance) (rate(prometheus_remote_storage_succeeded_samples_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]) or rate(prometheus_remote_storage_samples_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]))\n- \n (rate(prometheus_remote_storage_dropped_samples_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]) or rate(prometheus_remote_storage_samples_dropped_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]))\n",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate, in vs. succeeded or dropped [5m]",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Samples",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 5,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 6,
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "prometheus_remote_storage_shards{cluster=~\"$cluster\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Shards",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 6,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "prometheus_remote_storage_shards_max{cluster=~\"$cluster\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Max Shards",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 7,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "prometheus_remote_storage_shards_min{cluster=~\"$cluster\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Min Shards",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 8,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "prometheus_remote_storage_shards_desired{cluster=~\"$cluster\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Desired Shards",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Shards",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 9,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "prometheus_remote_storage_shard_capacity{cluster=~\"$cluster\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Shard Capacity",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 10,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "prometheus_remote_storage_pending_samples{cluster=~\"$cluster\", instance=~\"$instance\"} or prometheus_remote_storage_samples_pending{cluster=~\"$cluster\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Pending Samples",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Shard Details",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 11,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "prometheus_tsdb_wal_segment_current{cluster=~\"$cluster\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "TSDB Current Segment",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "none",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 12,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "prometheus_wal_watcher_current_segment{cluster=~\"$cluster\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}consumer{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Remote Write Current Segment",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "none",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Segments",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 13,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(prometheus_remote_storage_dropped_samples_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]) or rate(prometheus_remote_storage_samples_dropped_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m])",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Dropped Samples",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 14,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(prometheus_remote_storage_failed_samples_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]) or rate(prometheus_remote_storage_samples_failed_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m])",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Failed Samples",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 15,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(prometheus_remote_storage_retried_samples_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]) or rate(prometheus_remote_storage_samples_retried_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m])",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Retried Samples",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 16,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 3,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(prometheus_remote_storage_enqueue_retries_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m])",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Enqueue Retries",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Misc. Rates",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "prometheus-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "hide": 0,
+ "label": null,
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": {
+ "selected": true,
+ "text": "All",
+ "value": "$__all"
+ },
+ "value": {
+ "selected": true,
+ "text": "All",
+ "value": "$__all"
+ }
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(kube_pod_container_info{image=~\".*prometheus.*\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+ "text": {
+ "selected": true,
+ "text": "All",
+ "value": "$__all"
+ },
+ "value": {
+ "selected": true,
+ "text": "All",
+ "value": "$__all"
+ }
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "instance",
+ "options": [
+
+ ],
+ "query": "label_values(prometheus_build_info{cluster=~\"$cluster\"}, instance)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "url",
+ "options": [
+
+ ],
+ "query": "label_values(prometheus_remote_storage_shards{cluster=~\"$cluster\", instance=~\"$instance\"}, url)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-6h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Prometheus / Remote Write",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/prometheus.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/prometheus.yaml
new file mode 100644
index 00000000..124ee371
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/prometheus.yaml
@@ -0,0 +1,1235 @@
+{{- /*
+Generated from 'prometheus' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "prometheus" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ prometheus.json: |-
+ {
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "links": [
+
+ ],
+ "refresh": "60s",
+ "rows": [
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 1,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "styles": [
+ {
+ "alias": "Time",
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "pattern": "Time",
+ "type": "hidden"
+ },
+ {
+ "alias": "Count",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #A",
+ "thresholds": [
+
+ ],
+ "type": "hidden",
+ "unit": "short"
+ },
+ {
+ "alias": "Uptime",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "Value #B",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Instance",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "instance",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Job",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "job",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "Version",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "link": false,
+ "linkTargetBlank": false,
+ "linkTooltip": "Drill down",
+ "linkUrl": "",
+ "pattern": "version",
+ "thresholds": [
+
+ ],
+ "type": "number",
+ "unit": "short"
+ },
+ {
+ "alias": "",
+ "colorMode": null,
+ "colors": [
+
+ ],
+ "dateFormat": "YYYY-MM-DD HH:mm:ss",
+ "decimals": 2,
+ "pattern": "/.*/",
+ "thresholds": [
+
+ ],
+ "type": "string",
+ "unit": "short"
+ }
+ ],
+ "targets": [
+ {
+ "expr": "count by (job, instance, version) (prometheus_build_info{job=~\"$job\", instance=~\"$instance\"})",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A",
+ "step": 10
+ },
+ {
+ "expr": "max by (job, instance) (time() - process_start_time_seconds{job=~\"$job\", instance=~\"$instance\"})",
+ "format": "table",
+ "instant": true,
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "B",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Prometheus Stats",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "transform": "table",
+ "type": "table",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Prometheus Stats",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 2,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(prometheus_target_sync_length_seconds_sum{job=~\"$job\",instance=~\"$instance\"}[5m])) by (scrape_job) * 1e3",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}scrape_job{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Target Sync",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ms",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 3,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(prometheus_sd_discovered_targets{job=~\"$job\",instance=~\"$instance\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "Targets",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Targets",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Discovery",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "id": 4,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(prometheus_target_interval_length_seconds_sum{job=~\"$job\",instance=~\"$instance\"}[5m]) / rate(prometheus_target_interval_length_seconds_count{job=~\"$job\",instance=~\"$instance\"}[5m]) * 1e3",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}interval{{`}}`}} configured",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Scrape Interval Duration",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ms",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 5,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum by (job) (rate(prometheus_target_scrapes_exceeded_body_size_limit_total[1m]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "exceeded body size limit: {{`{{`}}job{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "sum by (job) (rate(prometheus_target_scrapes_exceeded_sample_limit_total[1m]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "exceeded sample limit: {{`{{`}}job{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "sum by (job) (rate(prometheus_target_scrapes_sample_duplicate_timestamp_total[1m]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "duplicate timestamp: {{`{{`}}job{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "sum by (job) (rate(prometheus_target_scrapes_sample_out_of_bounds_total[1m]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "out of bounds: {{`{{`}}job{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ },
+ {
+ "expr": "sum by (job) (rate(prometheus_target_scrapes_sample_out_of_order_total[1m]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "out of order: {{`{{`}}job{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Scrape failures",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 6,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(prometheus_tsdb_head_samples_appended_total{job=~\"$job\",instance=~\"$instance\"}[5m])",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}job{{`}}`}} {{`{{`}}instance{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Appended Samples",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Retrieval",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 7,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "prometheus_tsdb_head_series{job=~\"$job\",instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}job{{`}}`}} {{`{{`}}instance{{`}}`}} head series",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Head Series",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 8,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "prometheus_tsdb_head_chunks{job=~\"$job\",instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}job{{`}}`}} {{`{{`}}instance{{`}}`}} head chunks",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Head Chunks",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Storage",
+ "titleSize": "h6"
+ },
+ {
+ "collapse": false,
+ "height": "250px",
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 9,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(prometheus_engine_query_duration_seconds_count{job=~\"$job\",instance=~\"$instance\",slice=\"inner_eval\"}[5m])",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}job{{`}}`}} {{`{{`}}instance{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Query Rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 10,
+ "id": 10,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 0,
+ "links": [
+
+ ],
+ "nullPointMode": "null as zero",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "max by (slice) (prometheus_engine_query_duration_seconds{quantile=\"0.9\",job=~\"$job\",instance=~\"$instance\"}) * 1e3",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}slice{{`}}`}}",
+ "legendLink": null,
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Stage Duration",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ms",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Query",
+ "titleSize": "h6"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "prometheus-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": ".+",
+ "current": {
+ "selected": true,
+ "text": "All",
+ "value": "$__all"
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": true,
+ "label": "job",
+ "multi": true,
+ "name": "job",
+ "options": [
+
+ ],
+ "query": "label_values(prometheus_build_info{job=\"prometheus-k8s\",namespace=\"monitoring\"}, job)",
+ "refresh": 1,
+ "regex": "",
+ "sort": 2,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": ".+",
+ "current": {
+ "selected": true,
+ "text": "All",
+ "value": "$__all"
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": true,
+ "label": "instance",
+ "multi": true,
+ "name": "instance",
+ "options": [
+
+ ],
+ "query": "label_values(prometheus_build_info{job=~\"$job\"}, instance)",
+ "refresh": 1,
+ "regex": "",
+ "sort": 2,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Prometheus / Overview",
+ "uid": "",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/proxy.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/proxy.yaml
new file mode 100644
index 00000000..53a077c1
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/proxy.yaml
@@ -0,0 +1,1271 @@
+{{- /*
+Generated from 'proxy' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.kubeProxy.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "proxy" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ proxy.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": false,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "refresh": "10s",
+ "rows": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "$datasource",
+ "format": "none",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+
+ },
+ "id": 2,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "rightSide": true
+ },
+ "links": [
+
+ ],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 2,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(up{cluster=\"$cluster\", job=\"kube-proxy\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Up",
+ "tooltip": {
+ "shared": false
+ },
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "min"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 3,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 5,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(kubeproxy_sync_proxy_rules_duration_seconds_count{cluster=\"$cluster\", job=\"kube-proxy\", instance=~\"$instance\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "rate",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rules Sync Rate",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 4,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 5,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99,rate(kubeproxy_sync_proxy_rules_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-proxy\", instance=~\"$instance\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rule Sync Latency 99th Quantile",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 5,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(kubeproxy_network_programming_duration_seconds_count{cluster=\"$cluster\", job=\"kube-proxy\", instance=~\"$instance\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "rate",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Network Programming Rate",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 6,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 6,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(kubeproxy_network_programming_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-proxy\", instance=~\"$instance\"}[$__rate_interval])) by (instance, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Network Programming Latency 99th Quantile",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 7,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"kube-proxy\", instance=~\"$instance\",code=~\"2..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "2xx",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"kube-proxy\", instance=~\"$instance\",code=~\"3..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "3xx",
+ "refId": "B"
+ },
+ {
+ "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"kube-proxy\", instance=~\"$instance\",code=~\"4..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "4xx",
+ "refId": "C"
+ },
+ {
+ "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"kube-proxy\", instance=~\"$instance\",code=~\"5..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "5xx",
+ "refId": "D"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Kube API Request Rate",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 8,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 8,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-proxy\",instance=~\"$instance\",verb=\"POST\"}[$__rate_interval])) by (verb, url, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Post Request Latency 99th Quantile",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 9,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-proxy\", instance=~\"$instance\", verb=\"GET\"}[$__rate_interval])) by (verb, url, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Get Request Latency 99th Quantile",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 10,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "process_resident_memory_bytes{cluster=\"$cluster\", job=\"kube-proxy\",instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 11,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(process_cpu_seconds_total{cluster=\"$cluster\", job=\"kube-proxy\",instance=~\"$instance\"}[$__rate_interval])",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 12,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "go_goroutines{cluster=\"$cluster\", job=\"kube-proxy\",instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Goroutines",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": "cluster",
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kube-proxy\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "instance",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kube-proxy\", cluster=\"$cluster\", job=\"kube-proxy\"}, instance)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Proxy",
+ "uid": "632e265de029684c40b21cb76bca4f94",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/scheduler.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/scheduler.yaml
new file mode 100644
index 00000000..c7ac2072
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/scheduler.yaml
@@ -0,0 +1,1112 @@
+{{- /*
+Generated from 'scheduler' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.kubeScheduler.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "scheduler" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ scheduler.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+
+ ]
+ },
+ "editable": false,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "refresh": "10s",
+ "rows": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": false,
+ "colors": [
+ "#299c46",
+ "rgba(237, 129, 40, 0.89)",
+ "#d44a3a"
+ ],
+ "datasource": "$datasource",
+ "format": "none",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+
+ },
+ "id": 2,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "rightSide": true
+ },
+ "links": [
+
+ ],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "span": 2,
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": false
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "expr": "sum(up{cluster=\"$cluster\", job=\"kube-scheduler\"})",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "",
+ "refId": "A"
+ }
+ ],
+ "thresholds": "",
+ "title": "Up",
+ "tooltip": {
+ "shared": false
+ },
+ "type": "singlestat",
+ "valueFontSize": "80%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "min"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 3,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 5,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(scheduler_e2e_scheduling_duration_seconds_count{cluster=\"$cluster\", job=\"kube-scheduler\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} e2e",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(rate(scheduler_binding_duration_seconds_count{cluster=\"$cluster\", job=\"kube-scheduler\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} binding",
+ "refId": "B"
+ },
+ {
+ "expr": "sum(rate(scheduler_scheduling_algorithm_duration_seconds_count{cluster=\"$cluster\", job=\"kube-scheduler\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} scheduling algorithm",
+ "refId": "C"
+ },
+ {
+ "expr": "sum(rate(scheduler_volume_scheduling_duration_seconds_count{cluster=\"$cluster\", job=\"kube-scheduler\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance)",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} volume",
+ "refId": "D"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Scheduling Rate",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 4,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 5,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(scheduler_e2e_scheduling_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-scheduler\",instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} e2e",
+ "refId": "A"
+ },
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(scheduler_binding_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-scheduler\",instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} binding",
+ "refId": "B"
+ },
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(scheduler_scheduling_algorithm_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-scheduler\",instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} scheduling algorithm",
+ "refId": "C"
+ },
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(scheduler_volume_scheduling_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-scheduler\",instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} volume",
+ "refId": "D"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Scheduling latency 99th Quantile",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 5,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"kube-scheduler\", instance=~\"$instance\",code=~\"2..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "2xx",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"kube-scheduler\", instance=~\"$instance\",code=~\"3..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "3xx",
+ "refId": "B"
+ },
+ {
+ "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"kube-scheduler\", instance=~\"$instance\",code=~\"4..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "4xx",
+ "refId": "C"
+ },
+ {
+ "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"kube-scheduler\", instance=~\"$instance\",code=~\"5..\"}[$__rate_interval]))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "5xx",
+ "refId": "D"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Kube API Request Rate",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "ops",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 6,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 8,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-scheduler\", instance=~\"$instance\", verb=\"POST\"}[$__rate_interval])) by (verb, url, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Post Request Latency 99th Quantile",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 7,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\", job=\"kube-scheduler\", instance=~\"$instance\", verb=\"GET\"}[$__rate_interval])) by (verb, url, le))",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Get Request Latency 99th Quantile",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "s",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 8,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "process_resident_memory_bytes{cluster=\"$cluster\", job=\"kube-scheduler\", instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Memory",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 9,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "rate(process_cpu_seconds_total{cluster=\"$cluster\", job=\"kube-scheduler\", instance=~\"$instance\"}[$__rate_interval])",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "CPU usage",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "bytes",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 1,
+ "fillGradient": 0,
+ "gridPos": {
+
+ },
+ "id": 10,
+ "interval": "1m",
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 4,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "go_goroutines{cluster=\"$cluster\", job=\"kube-scheduler\",instance=~\"$instance\"}",
+ "format": "time_series",
+ "intervalFactor": 2,
+ "legendFormat": "{{`{{`}}instance{{`}}`}}",
+ "refId": "A"
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Goroutines",
+ "tooltip": {
+ "shared": false,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": false,
+ "title": "Dashboard Row",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "schemaVersion": 14,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": "cluster",
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kube-scheduler\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "instance",
+ "options": [
+
+ ],
+ "query": "label_values(up{job=\"kube-scheduler\", cluster=\"$cluster\"}, instance)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Scheduler",
+ "uid": "2e6b6a3b4bddf1427b3a55aa1311c656",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/grafana/dashboards-1.14/workload-total.yaml b/kube-prometheus-stack/templates/grafana/dashboards-1.14/workload-total.yaml
new file mode 100644
index 00000000..35ca442b
--- /dev/null
+++ b/kube-prometheus-stack/templates/grafana/dashboards-1.14/workload-total.yaml
@@ -0,0 +1,1438 @@
+{{- /*
+Generated from 'workload-total' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/grafana-dashboardDefinitions.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }}
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "workload-total" | trunc 63 | trimSuffix "-" }}
+ annotations:
+{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }}
+ labels:
+ {{- if $.Values.grafana.sidecar.dashboards.label }}
+ {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }}
+ {{- end }}
+ app: {{ template "kube-prometheus-stack.name" $ }}-grafana
+{{ include "kube-prometheus-stack.labels" $ | indent 4 }}
+data:
+ workload-total.json: |-
+ {
+ "__inputs": [
+
+ ],
+ "__requires": [
+
+ ],
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": "-- Grafana --",
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "gnetId": null,
+ "graphTooltip": 0,
+ "hideControls": false,
+ "id": null,
+ "links": [
+
+ ],
+ "panels": [
+ {
+ "collapse": false,
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 2,
+ "panels": [
+
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Current Bandwidth",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": true,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 1
+ },
+ "id": 3,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": false,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}} pod {{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Rate of Bytes Received",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "series",
+ "name": null,
+ "show": false,
+ "values": [
+ "current"
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": true,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 1
+ },
+ "id": 4,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": false,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}} pod {{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Current Rate of Bytes Transmitted",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "series",
+ "name": null,
+ "show": false,
+ "values": [
+ "current"
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 10
+ },
+ "id": 5,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": true,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 11
+ },
+ "id": 6,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": false,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(avg(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}} pod {{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Rate of Bytes Received",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "series",
+ "name": null,
+ "show": false,
+ "values": [
+ "current"
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": true,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 11
+ },
+ "id": 7,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": true,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "sideWidth": null,
+ "sort": "current",
+ "sortDesc": true,
+ "total": false,
+ "values": true
+ },
+ "lines": false,
+ "linewidth": 1,
+ "links": [
+
+ ],
+ "minSpan": 24,
+ "nullPointMode": "null",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 24,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(avg(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}} pod {{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Average Rate of Bytes Transmitted",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "series",
+ "name": null,
+ "show": false,
+ "values": [
+ "current"
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Average Bandwidth",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": false,
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 11
+ },
+ "id": 8,
+ "panels": [
+
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Bandwidth HIstory",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 12
+ },
+ "id": 9,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Receive Bandwidth",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 12
+ },
+ "id": 10,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Transmit Bandwidth",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "Bps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 21
+ },
+ "id": 11,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 22
+ },
+ "id": 12,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 22
+ },
+ "id": 13,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Packets",
+ "titleSize": "h6",
+ "type": "row"
+ },
+ {
+ "collapse": true,
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 22
+ },
+ "id": 14,
+ "panels": [
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 23
+ },
+ "id": 15,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_receive_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Received Packets Dropped",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ },
+ {
+ "aliasColors": {
+
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "$datasource",
+ "fill": 2,
+ "fillGradient": 0,
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 23
+ },
+ "id": 16,
+ "legend": {
+ "alignAsTable": false,
+ "avg": false,
+ "current": false,
+ "hideEmpty": true,
+ "hideZero": true,
+ "max": false,
+ "min": false,
+ "rightSide": false,
+ "show": true,
+ "sideWidth": null,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 2,
+ "links": [
+
+ ],
+ "minSpan": 12,
+ "nullPointMode": "connected",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 5,
+ "points": false,
+ "renderer": "flot",
+ "repeat": null,
+ "seriesOverrides": [
+
+ ],
+ "spaceLength": 10,
+ "span": 12,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sort_desc(sum(irate(container_network_transmit_packets_dropped_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "{{`{{`}}pod{{`}}`}}",
+ "refId": "A",
+ "step": 10
+ }
+ ],
+ "thresholds": [
+
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Rate of Transmitted Packets Dropped",
+ "tooltip": {
+ "shared": true,
+ "sort": 2,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": [
+
+ ]
+ },
+ "yaxes": [
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ },
+ {
+ "format": "pps",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": 0,
+ "show": true
+ }
+ ]
+ }
+ ],
+ "repeat": null,
+ "repeatIteration": null,
+ "repeatRowId": null,
+ "showTitle": true,
+ "title": "Errors",
+ "titleSize": "h6",
+ "type": "row"
+ }
+ ],
+ "refresh": "10s",
+ "rows": [
+
+ ],
+ "schemaVersion": 18,
+ "style": "dark",
+ "tags": [
+ "kubernetes-mixin"
+ ],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "text": "default",
+ "value": "default"
+ },
+ "hide": 0,
+ "label": "Data Source",
+ "name": "datasource",
+ "options": [
+
+ ],
+ "query": "prometheus",
+ "refresh": 1,
+ "regex": "",
+ "type": "datasource"
+ },
+ {
+ "allValue": null,
+ "current": {
+
+ },
+ "datasource": "$datasource",
+ "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }},
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "cluster",
+ "options": [
+
+ ],
+ "query": "label_values(kube_pod_info{job=\"kube-state-metrics\"}, cluster)",
+ "refresh": 2,
+ "regex": "",
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": ".+",
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "kube-system",
+ "value": "kube-system"
+ },
+ "datasource": "$datasource",
+ "definition": "label_values(container_network_receive_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\"}, namespace)",
+ "hide": 0,
+ "includeAll": true,
+ "label": null,
+ "multi": false,
+ "name": "namespace",
+ "options": [
+
+ ],
+ "query": "label_values(container_network_receive_packets_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\"}, namespace)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "",
+ "value": ""
+ },
+ "datasource": "$datasource",
+ "definition": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\"}, workload)",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "workload",
+ "options": [
+
+ ],
+ "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\"}, workload)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "deployment",
+ "value": "deployment"
+ },
+ "datasource": "$datasource",
+ "definition": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\"}, workload_type)",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "type",
+ "options": [
+
+ ],
+ "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\"}, workload_type)",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 0,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "query",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "5m",
+ "value": "5m"
+ },
+ "datasource": "$datasource",
+ "hide": 0,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "resolution",
+ "options": [
+ {
+ "selected": false,
+ "text": "30s",
+ "value": "30s"
+ },
+ {
+ "selected": true,
+ "text": "5m",
+ "value": "5m"
+ },
+ {
+ "selected": false,
+ "text": "1h",
+ "value": "1h"
+ }
+ ],
+ "query": "30s,5m,1h",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "interval",
+ "useTags": false
+ },
+ {
+ "allValue": null,
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "text": "5m",
+ "value": "5m"
+ },
+ "datasource": "$datasource",
+ "hide": 2,
+ "includeAll": false,
+ "label": null,
+ "multi": false,
+ "name": "interval",
+ "options": [
+ {
+ "selected": true,
+ "text": "4h",
+ "value": "4h"
+ }
+ ],
+ "query": "4h",
+ "refresh": 2,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "tagValuesQuery": "",
+ "tags": [
+
+ ],
+ "tagsQuery": "",
+ "type": "interval",
+ "useTags": false
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "5s",
+ "10s",
+ "30s",
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ],
+ "time_options": [
+ "5m",
+ "15m",
+ "1h",
+ "6h",
+ "12h",
+ "24h",
+ "2d",
+ "7d",
+ "30d"
+ ]
+ },
+ "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}",
+ "title": "Kubernetes / Networking / Workload",
+ "uid": "728bf77cc1166d2f3133bf25846876cc",
+ "version": 0
+ }
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/clusterrole.yaml b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/clusterrole.yaml
new file mode 100644
index 00000000..6c91ee00
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/clusterrole.yaml
@@ -0,0 +1,33 @@
+{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled .Values.global.rbac.create (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ annotations:
+ "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
+ "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-admission
+{{- include "kube-prometheus-stack.labels" $ | indent 4 }}
+rules:
+ - apiGroups:
+ - admissionregistration.k8s.io
+ resources:
+ - validatingwebhookconfigurations
+ - mutatingwebhookconfigurations
+ verbs:
+ - get
+ - update
+{{- if .Values.global.rbac.pspEnabled }}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if semverCompare "> 1.15.0-0" $kubeTargetVersion }}
+ - apiGroups: ['policy']
+{{- else }}
+ - apiGroups: ['extensions']
+{{- end }}
+ resources: ['podsecuritypolicies']
+ verbs: ['use']
+ resourceNames:
+ - {{ template "kube-prometheus-stack.fullname" . }}-admission
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/clusterrolebinding.yaml b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/clusterrolebinding.yaml
new file mode 100644
index 00000000..b909d14e
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/clusterrolebinding.yaml
@@ -0,0 +1,20 @@
+{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled .Values.global.rbac.create (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ annotations:
+ "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
+ "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-admission
+{{- include "kube-prometheus-stack.labels" $ | indent 4 }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+subjects:
+ - kind: ServiceAccount
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/job-createSecret.yaml b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/job-createSecret.yaml
new file mode 100644
index 00000000..abe36380
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/job-createSecret.yaml
@@ -0,0 +1,69 @@
+{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }}
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission-create
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ annotations:
+ "helm.sh/hook": pre-install,pre-upgrade
+ "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-admission-create
+{{- include "kube-prometheus-stack.labels" $ | indent 4 }}
+spec:
+ {{- if .Capabilities.APIVersions.Has "batch/v1alpha1" }}
+ # Alpha feature since k8s 1.12
+ ttlSecondsAfterFinished: 0
+ {{- end }}
+ template:
+ metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission-create
+{{- with .Values.prometheusOperator.admissionWebhooks.patch.podAnnotations }}
+ annotations:
+{{ toYaml . | indent 8 }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-admission-create
+{{- include "kube-prometheus-stack.labels" $ | indent 8 }}
+ spec:
+ {{- if .Values.prometheusOperator.admissionWebhooks.patch.priorityClassName }}
+ priorityClassName: {{ .Values.prometheusOperator.admissionWebhooks.patch.priorityClassName }}
+ {{- end }}
+ containers:
+ - name: create
+ {{- if .Values.prometheusOperator.admissionWebhooks.patch.image.sha }}
+ image: {{ .Values.prometheusOperator.admissionWebhooks.patch.image.repository }}:{{ .Values.prometheusOperator.admissionWebhooks.patch.image.tag }}@sha256:{{ .Values.prometheusOperator.admissionWebhooks.patch.image.sha }}
+ {{- else }}
+ image: {{ .Values.prometheusOperator.admissionWebhooks.patch.image.repository }}:{{ .Values.prometheusOperator.admissionWebhooks.patch.image.tag }}
+ {{- end }}
+ imagePullPolicy: {{ .Values.prometheusOperator.admissionWebhooks.patch.image.pullPolicy }}
+ args:
+ - create
+ - --host={{ template "kube-prometheus-stack.operator.fullname" . }},{{ template "kube-prometheus-stack.operator.fullname" . }}.{{ template "kube-prometheus-stack.namespace" . }}.svc
+ - --namespace={{ template "kube-prometheus-stack.namespace" . }}
+ - --secret-name={{ template "kube-prometheus-stack.fullname" . }}-admission
+ {{- with .Values.prometheusOperator.admissionWebhooks.createSecretJob }}
+ securityContext:
+ {{ toYaml .securityContext | nindent 12 }}
+ {{- end }}
+ resources:
+{{ toYaml .Values.prometheusOperator.admissionWebhooks.patch.resources | indent 12 }}
+ restartPolicy: OnFailure
+ serviceAccountName: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ {{- with .Values.prometheusOperator.admissionWebhooks.patch.nodeSelector }}
+ nodeSelector:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ {{- with .Values.prometheusOperator.admissionWebhooks.patch.affinity }}
+ affinity:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ {{- with .Values.prometheusOperator.admissionWebhooks.patch.tolerations }}
+ tolerations:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+{{- if .Values.prometheusOperator.admissionWebhooks.patch.securityContext }}
+ securityContext:
+{{ toYaml .Values.prometheusOperator.admissionWebhooks.patch.securityContext | indent 8 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/job-patchWebhook.yaml b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/job-patchWebhook.yaml
new file mode 100644
index 00000000..560dc11f
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/job-patchWebhook.yaml
@@ -0,0 +1,70 @@
+{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }}
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission-patch
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ annotations:
+ "helm.sh/hook": post-install,post-upgrade
+ "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-admission-patch
+{{- include "kube-prometheus-stack.labels" $ | indent 4 }}
+spec:
+ {{- if .Capabilities.APIVersions.Has "batch/v1alpha1" }}
+ # Alpha feature since k8s 1.12
+ ttlSecondsAfterFinished: 0
+ {{- end }}
+ template:
+ metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission-patch
+{{- with .Values.prometheusOperator.admissionWebhooks.patch.podAnnotations }}
+ annotations:
+{{ toYaml . | indent 8 }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-admission-patch
+{{- include "kube-prometheus-stack.labels" $ | indent 8 }}
+ spec:
+ {{- if .Values.prometheusOperator.admissionWebhooks.patch.priorityClassName }}
+ priorityClassName: {{ .Values.prometheusOperator.admissionWebhooks.patch.priorityClassName }}
+ {{- end }}
+ containers:
+ - name: patch
+ {{- if .Values.prometheusOperator.admissionWebhooks.patch.image.sha }}
+ image: {{ .Values.prometheusOperator.admissionWebhooks.patch.image.repository }}:{{ .Values.prometheusOperator.admissionWebhooks.patch.image.tag }}@sha256:{{ .Values.prometheusOperator.admissionWebhooks.patch.image.sha }}
+ {{- else }}
+ image: {{ .Values.prometheusOperator.admissionWebhooks.patch.image.repository }}:{{ .Values.prometheusOperator.admissionWebhooks.patch.image.tag }}
+ {{- end }}
+ imagePullPolicy: {{ .Values.prometheusOperator.admissionWebhooks.patch.image.pullPolicy }}
+ args:
+ - patch
+ - --webhook-name={{ template "kube-prometheus-stack.fullname" . }}-admission
+ - --namespace={{ template "kube-prometheus-stack.namespace" . }}
+ - --secret-name={{ template "kube-prometheus-stack.fullname" . }}-admission
+ - --patch-failure-policy={{ .Values.prometheusOperator.admissionWebhooks.failurePolicy }}
+ {{- with .Values.prometheusOperator.admissionWebhooks.patchWebhookJob }}
+ securityContext:
+ {{ toYaml .securityContext | nindent 12 }}
+ {{- end }}
+ resources:
+{{ toYaml .Values.prometheusOperator.admissionWebhooks.patch.resources | indent 12 }}
+ restartPolicy: OnFailure
+ serviceAccountName: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ {{- with .Values.prometheusOperator.admissionWebhooks.patch.nodeSelector }}
+ nodeSelector:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ {{- with .Values.prometheusOperator.admissionWebhooks.patch.affinity }}
+ affinity:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ {{- with .Values.prometheusOperator.admissionWebhooks.patch.tolerations }}
+ tolerations:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+{{- if .Values.prometheusOperator.admissionWebhooks.patch.securityContext }}
+ securityContext:
+{{ toYaml .Values.prometheusOperator.admissionWebhooks.patch.securityContext | indent 8 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/psp.yaml b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/psp.yaml
new file mode 100644
index 00000000..9feff52d
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/psp.yaml
@@ -0,0 +1,47 @@
+{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }}
+apiVersion: policy/v1beta1
+kind: PodSecurityPolicy
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ annotations:
+ "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
+ "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
+{{- if .Values.global.rbac.pspAnnotations }}
+{{ toYaml .Values.global.rbac.pspAnnotations | indent 4 }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-admission
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ privileged: false
+ # Allow core volume types.
+ volumes:
+ - 'configMap'
+ - 'emptyDir'
+ - 'projected'
+ - 'secret'
+ - 'downwardAPI'
+ - 'persistentVolumeClaim'
+ hostNetwork: false
+ hostIPC: false
+ hostPID: false
+ runAsUser:
+ # Permits the container to run with root privileges as well.
+ rule: 'RunAsAny'
+ seLinux:
+ # This policy assumes the nodes are using AppArmor rather than SELinux.
+ rule: 'RunAsAny'
+ supplementalGroups:
+ rule: 'MustRunAs'
+ ranges:
+ # Allow adding the root group.
+ - min: 0
+ max: 65535
+ fsGroup:
+ rule: 'MustRunAs'
+ ranges:
+ # Allow adding the root group.
+ - min: 0
+ max: 65535
+ readOnlyRootFilesystem: false
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/role.yaml b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/role.yaml
new file mode 100644
index 00000000..a64e982a
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/role.yaml
@@ -0,0 +1,21 @@
+{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled .Values.global.rbac.create (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ annotations:
+ "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
+ "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-admission
+{{- include "kube-prometheus-stack.labels" $ | indent 4 }}
+rules:
+ - apiGroups:
+ - ""
+ resources:
+ - secrets
+ verbs:
+ - get
+ - create
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/rolebinding.yaml b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/rolebinding.yaml
new file mode 100644
index 00000000..d7136298
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/rolebinding.yaml
@@ -0,0 +1,21 @@
+{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled .Values.global.rbac.create (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ annotations:
+ "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
+ "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-admission
+{{- include "kube-prometheus-stack.labels" $ | indent 4 }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+subjects:
+ - kind: ServiceAccount
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/serviceaccount.yaml b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/serviceaccount.yaml
new file mode 100644
index 00000000..4fd52ae0
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/serviceaccount.yaml
@@ -0,0 +1,17 @@
+{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled .Values.global.rbac.create (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ annotations:
+ "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
+ "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-admission
+{{- include "kube-prometheus-stack.labels" $ | indent 4 }}
+{{- if .Values.global.imagePullSecrets }}
+imagePullSecrets:
+{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 2 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/mutatingWebhookConfiguration.yaml b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/mutatingWebhookConfiguration.yaml
new file mode 100644
index 00000000..7a12754e
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/mutatingWebhookConfiguration.yaml
@@ -0,0 +1,42 @@
+{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled }}
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+{{- if .Values.prometheusOperator.admissionWebhooks.certManager.enabled }}
+ annotations:
+ certmanager.k8s.io/inject-ca-from: {{ printf "%s/%s-admission" .Release.Namespace (include "kube-prometheus-stack.fullname" .) | quote }}
+ cert-manager.io/inject-ca-from: {{ printf "%s/%s-admission" .Release.Namespace (include "kube-prometheus-stack.fullname" .) | quote }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-admission
+{{- include "kube-prometheus-stack.labels" $ | indent 4 }}
+webhooks:
+ - name: prometheusrulemutate.monitoring.coreos.com
+ {{- if .Values.prometheusOperator.admissionWebhooks.patch.enabled }}
+ failurePolicy: Ignore
+ {{- else }}
+ failurePolicy: {{ .Values.prometheusOperator.admissionWebhooks.failurePolicy }}
+ {{- end }}
+ rules:
+ - apiGroups:
+ - monitoring.coreos.com
+ apiVersions:
+ - "*"
+ resources:
+ - prometheusrules
+ operations:
+ - CREATE
+ - UPDATE
+ clientConfig:
+ service:
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ name: {{ template "kube-prometheus-stack.operator.fullname" $ }}
+ path: /admission-prometheusrules/mutate
+ {{- if and .Values.prometheusOperator.admissionWebhooks.caBundle (not .Values.prometheusOperator.admissionWebhooks.patch.enabled) (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }}
+ caBundle: {{ .Values.prometheusOperator.admissionWebhooks.caBundle }}
+ {{- end }}
+ timeoutSeconds: {{ .Values.prometheusOperator.admissionWebhooks.timeoutSeconds }}
+ admissionReviewVersions: ["v1", "v1beta1"]
+ sideEffects: None
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/validatingWebhookConfiguration.yaml b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/validatingWebhookConfiguration.yaml
new file mode 100644
index 00000000..92426594
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/validatingWebhookConfiguration.yaml
@@ -0,0 +1,41 @@
+{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled }}
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+{{- if .Values.prometheusOperator.admissionWebhooks.certManager.enabled }}
+ annotations:
+ certmanager.k8s.io/inject-ca-from: {{ printf "%s/%s-admission" .Release.Namespace (include "kube-prometheus-stack.fullname" .) | quote }}
+ cert-manager.io/inject-ca-from: {{ printf "%s/%s-admission" .Release.Namespace (include "kube-prometheus-stack.fullname" .) | quote }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-admission
+{{- include "kube-prometheus-stack.labels" $ | indent 4 }}
+webhooks:
+ - name: prometheusrulemutate.monitoring.coreos.com
+ {{- if .Values.prometheusOperator.admissionWebhooks.patch.enabled }}
+ failurePolicy: Ignore
+ {{- else }}
+ failurePolicy: {{ .Values.prometheusOperator.admissionWebhooks.failurePolicy }}
+ {{- end }}
+ rules:
+ - apiGroups:
+ - monitoring.coreos.com
+ apiVersions:
+ - "*"
+ resources:
+ - prometheusrules
+ operations:
+ - CREATE
+ - UPDATE
+ clientConfig:
+ service:
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ name: {{ template "kube-prometheus-stack.operator.fullname" $ }}
+ path: /admission-prometheusrules/validate
+ {{- if and .Values.prometheusOperator.admissionWebhooks.caBundle (not .Values.prometheusOperator.admissionWebhooks.patch.enabled) (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }}
+ caBundle: {{ .Values.prometheusOperator.admissionWebhooks.caBundle }}
+ {{- end }}
+ admissionReviewVersions: ["v1", "v1beta1"]
+ sideEffects: None
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/aggregate-clusterroles.yaml b/kube-prometheus-stack/templates/prometheus-operator/aggregate-clusterroles.yaml
new file mode 100644
index 00000000..d15bb9e0
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/aggregate-clusterroles.yaml
@@ -0,0 +1,31 @@
+{{/* This file is based on https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/rbac-crd.md */}}
+{{- if and .Values.global.rbac.create .Values.global.rbac.createAggregateClusterRoles }}
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-crd-view
+ labels:
+ rbac.authorization.k8s.io/aggregate-to-admin: "true"
+ rbac.authorization.k8s.io/aggregate-to-edit: "true"
+ rbac.authorization.k8s.io/aggregate-to-view: "true"
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+ {{- include "kube-prometheus-stack.labels" . | nindent 4 }}
+rules:
+- apiGroups: ["monitoring.coreos.com"]
+ resources: ["alertmanagers", "alertmanagerconfigs", "prometheuses", "prometheusrules", "servicemonitors", "podmonitors", "probes"]
+ verbs: ["get", "list", "watch"]
+---
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-crd-edit
+ labels:
+ rbac.authorization.k8s.io/aggregate-to-edit: "true"
+ rbac.authorization.k8s.io/aggregate-to-admin: "true"
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+ {{- include "kube-prometheus-stack.labels" . | nindent 4 }}
+rules:
+- apiGroups: ["monitoring.coreos.com"]
+ resources: ["alertmanagers", "alertmanagerconfigs", "prometheuses", "prometheusrules", "servicemonitors", "podmonitors", "probes"]
+ verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/certmanager.yaml b/kube-prometheus-stack/templates/prometheus-operator/certmanager.yaml
new file mode 100644
index 00000000..a1e06aec
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/certmanager.yaml
@@ -0,0 +1,57 @@
+{{- if .Values.prometheusOperator.admissionWebhooks.certManager.enabled -}}
+{{- if not .Values.prometheusOperator.admissionWebhooks.certManager.issuerRef -}}
+# Create a selfsigned Issuer, in order to create a root CA certificate for
+# signing webhook serving certificates
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-self-signed-issuer
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+spec:
+ selfSigned: {}
+---
+# Generate a CA Certificate used to sign certificates for the webhook
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-root-cert
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+spec:
+ secretName: {{ template "kube-prometheus-stack.fullname" . }}-root-cert
+ duration: {{ .Values.prometheusOperator.admissionWebhooks.certManager.rootCert.duration | default "43800h0m0s" | quote }}
+ issuerRef:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-self-signed-issuer
+ commonName: "ca.webhook.kube-prometheus-stack"
+ isCA: true
+---
+# Create an Issuer that uses the above generated CA certificate to issue certs
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-root-issuer
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+spec:
+ ca:
+ secretName: {{ template "kube-prometheus-stack.fullname" . }}-root-cert
+{{- end }}
+---
+# generate a server certificate for the apiservices to use
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+spec:
+ secretName: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ duration: {{ .Values.prometheusOperator.admissionWebhooks.certManager.admissionCert.duration | default "8760h0m0s" | quote }}
+ issuerRef:
+ {{- if .Values.prometheusOperator.admissionWebhooks.certManager.issuerRef }}
+ {{- toYaml .Values.prometheusOperator.admissionWebhooks.certManager.issuerRef | nindent 4 }}
+ {{- else }}
+ name: {{ template "kube-prometheus-stack.fullname" . }}-root-issuer
+ {{- end }}
+ dnsNames:
+ - {{ template "kube-prometheus-stack.operator.fullname" . }}
+ - {{ template "kube-prometheus-stack.operator.fullname" . }}.{{ template "kube-prometheus-stack.namespace" . }}
+ - {{ template "kube-prometheus-stack.operator.fullname" . }}.{{ template "kube-prometheus-stack.namespace" . }}.svc
+{{- end -}}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/clusterrole.yaml b/kube-prometheus-stack/templates/prometheus-operator/clusterrole.yaml
new file mode 100644
index 00000000..300956a1
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/clusterrole.yaml
@@ -0,0 +1,81 @@
+{{- if and .Values.prometheusOperator.enabled .Values.global.rbac.create }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-operator
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+rules:
+- apiGroups:
+ - monitoring.coreos.com
+ resources:
+ - alertmanagers
+ - alertmanagers/finalizers
+ - alertmanagerconfigs
+ - prometheuses
+ - prometheuses/status
+ - prometheuses/finalizers
+ - thanosrulers
+ - thanosrulers/finalizers
+ - servicemonitors
+ - podmonitors
+ - probes
+ - prometheusrules
+ verbs:
+ - '*'
+- apiGroups:
+ - apps
+ resources:
+ - statefulsets
+ verbs:
+ - '*'
+- apiGroups:
+ - ""
+ resources:
+ - configmaps
+ - secrets
+ verbs:
+ - '*'
+- apiGroups:
+ - ""
+ resources:
+ - pods
+ verbs:
+ - list
+ - delete
+- apiGroups:
+ - ""
+ resources:
+ - services
+ - services/finalizers
+ - endpoints
+ verbs:
+ - get
+ - create
+ - update
+ - delete
+- apiGroups:
+ - ""
+ resources:
+ - nodes
+ verbs:
+ - list
+ - watch
+- apiGroups:
+ - ""
+ resources:
+ - namespaces
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups:
+ - networking.k8s.io
+ resources:
+ - ingresses
+ verbs:
+ - get
+ - list
+ - watch
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/clusterrolebinding.yaml b/kube-prometheus-stack/templates/prometheus-operator/clusterrolebinding.yaml
new file mode 100644
index 00000000..c9ab0ab8
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/clusterrolebinding.yaml
@@ -0,0 +1,17 @@
+{{- if and .Values.prometheusOperator.enabled .Values.global.rbac.create }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-operator
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: {{ template "kube-prometheus-stack.fullname" . }}-operator
+subjects:
+- kind: ServiceAccount
+ name: {{ template "kube-prometheus-stack.operator.serviceAccountName" . }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/deployment.yaml b/kube-prometheus-stack/templates/prometheus-operator/deployment.yaml
new file mode 100644
index 00000000..c3888b95
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/deployment.yaml
@@ -0,0 +1,167 @@
+{{- $namespace := printf "%s" (include "kube-prometheus-stack.namespace" .) }}
+{{- $defaultKubeletSvcName := printf "%s-kubelet" (include "kube-prometheus-stack.fullname" .) }}
+{{- if .Values.prometheusOperator.enabled }}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-operator
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.prometheusOperator.labels }}
+{{ toYaml .Values.prometheusOperator.labels | indent 4 }}
+{{- end }}
+{{- if .Values.prometheusOperator.annotations }}
+ annotations:
+{{ toYaml .Values.prometheusOperator.annotations | indent 4 }}
+{{- end }}
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+ release: {{ $.Release.Name | quote }}
+ template:
+ metadata:
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+{{ include "kube-prometheus-stack.labels" . | indent 8 }}
+{{- if .Values.prometheusOperator.podLabels }}
+{{ toYaml .Values.prometheusOperator.podLabels | indent 8 }}
+{{- end }}
+{{- if .Values.prometheusOperator.podAnnotations }}
+ annotations:
+{{ toYaml .Values.prometheusOperator.podAnnotations | indent 8 }}
+{{- end }}
+ spec:
+ {{- if .Values.prometheusOperator.priorityClassName }}
+ priorityClassName: {{ .Values.prometheusOperator.priorityClassName }}
+ {{- end }}
+ containers:
+ - name: {{ template "kube-prometheus-stack.name" . }}
+ {{- if .Values.prometheusOperator.image.sha }}
+ image: "{{ .Values.prometheusOperator.image.repository }}:{{ .Values.prometheusOperator.image.tag }}@sha256:{{ .Values.prometheusOperator.image.sha }}"
+ {{- else }}
+ image: "{{ .Values.prometheusOperator.image.repository }}:{{ .Values.prometheusOperator.image.tag }}"
+ {{- end }}
+ imagePullPolicy: "{{ .Values.prometheusOperator.image.pullPolicy }}"
+ args:
+ {{- if .Values.prometheusOperator.kubeletService.enabled }}
+ - --kubelet-service={{ .Values.prometheusOperator.kubeletService.namespace }}/{{ default $defaultKubeletSvcName .Values.prometheusOperator.kubeletService.name }}
+ {{- end }}
+ {{- if .Values.prometheusOperator.logFormat }}
+ - --log-format={{ .Values.prometheusOperator.logFormat }}
+ {{- end }}
+ {{- if .Values.prometheusOperator.logLevel }}
+ - --log-level={{ .Values.prometheusOperator.logLevel }}
+ {{- end }}
+ {{- if .Values.prometheusOperator.denyNamespaces }}
+ - --deny-namespaces={{ tpl (.Values.prometheusOperator.denyNamespaces | join ",") $ }}
+ {{- end }}
+ {{- with $.Values.prometheusOperator.namespaces }}
+ {{- $namespaces := list }}
+ {{- if .releaseNamespace }}
+ {{- $namespaces = append $namespaces $namespace }}
+ {{- end }}
+ {{- if .additional }}
+ {{- range $ns := .additional }}
+ {{- $namespaces = append $namespaces (tpl $ns $) }}
+ {{- end }}
+ {{- end }}
+ - --namespaces={{ $namespaces | mustUniq | join "," }}
+ {{- end }}
+ - --localhost=127.0.0.1
+ {{- if .Values.prometheusOperator.prometheusDefaultBaseImage }}
+ - --prometheus-default-base-image={{ .Values.prometheusOperator.prometheusDefaultBaseImage }}
+ {{- end }}
+ {{- if .Values.prometheusOperator.alertmanagerDefaultBaseImage }}
+ - --alertmanager-default-base-image={{ .Values.prometheusOperator.alertmanagerDefaultBaseImage }}
+ {{- end }}
+ {{- if .Values.prometheusOperator.prometheusConfigReloader.image.sha }}
+ - --prometheus-config-reloader={{ .Values.prometheusOperator.prometheusConfigReloader.image.repository }}:{{ .Values.prometheusOperator.prometheusConfigReloader.image.tag }}@sha256:{{ .Values.prometheusOperator.prometheusConfigReloader.image.sha }}
+ {{- else }}
+ - --prometheus-config-reloader={{ .Values.prometheusOperator.prometheusConfigReloader.image.repository }}:{{ .Values.prometheusOperator.prometheusConfigReloader.image.tag }}
+ {{- end }}
+ - --config-reloader-cpu-request={{ .Values.prometheusOperator.prometheusConfigReloader.resources.requests.cpu }}
+ - --config-reloader-cpu-limit={{ .Values.prometheusOperator.prometheusConfigReloader.resources.limits.cpu }}
+ - --config-reloader-memory-request={{ .Values.prometheusOperator.prometheusConfigReloader.resources.requests.memory }}
+ - --config-reloader-memory-limit={{ .Values.prometheusOperator.prometheusConfigReloader.resources.limits.memory }}
+ {{- if .Values.prometheusOperator.alertmanagerInstanceNamespaces }}
+ - --alertmanager-instance-namespaces={{ .Values.prometheusOperator.alertmanagerInstanceNamespaces | join "," }}
+ {{- end }}
+ {{- if .Values.prometheusOperator.alertmanagerConfigNamespaces }}
+ - --alertmanager-config-namespaces={{ .Values.prometheusOperator.alertmanagerConfigNamespaces | join "," }}
+ {{- end }}
+ {{- if .Values.prometheusOperator.prometheusInstanceNamespaces }}
+ - --prometheus-instance-namespaces={{ .Values.prometheusOperator.prometheusInstanceNamespaces | join "," }}
+ {{- end }}
+ {{- if .Values.prometheusOperator.thanosImage.sha }}
+ - --thanos-default-base-image={{ .Values.prometheusOperator.thanosImage.repository }}:{{ .Values.prometheusOperator.thanosImage.tag }}@sha256:{{ .Values.prometheusOperator.thanosImage.sha }}
+ {{- else }}
+ - --thanos-default-base-image={{ .Values.prometheusOperator.thanosImage.repository }}:{{ .Values.prometheusOperator.thanosImage.tag }}
+ {{- end }}
+ {{- if .Values.prometheusOperator.thanosRulerInstanceNamespaces }}
+ - --thanos-ruler-instance-namespaces={{ .Values.prometheusOperator.thanosRulerInstanceNamespaces | join "," }}
+ {{- end }}
+ {{- if .Values.prometheusOperator.secretFieldSelector }}
+ - --secret-field-selector={{ .Values.prometheusOperator.secretFieldSelector }}
+ {{- end }}
+ {{- if .Values.prometheusOperator.clusterDomain }}
+ - --cluster-domain={{ .Values.prometheusOperator.clusterDomain }}
+ {{- end }}
+ {{- if .Values.prometheusOperator.tls.enabled }}
+ - --web.enable-tls=true
+ - --web.cert-file=/cert/{{ if .Values.prometheusOperator.admissionWebhooks.certManager.enabled }}tls.crt{{ else }}cert{{ end }}
+ - --web.key-file=/cert/{{ if .Values.prometheusOperator.admissionWebhooks.certManager.enabled }}tls.key{{ else }}key{{ end }}
+ - --web.listen-address=:{{ .Values.prometheusOperator.tls.internalPort }}
+ - --web.tls-min-version={{ .Values.prometheusOperator.tls.tlsMinVersion }}
+ ports:
+ - containerPort: {{ .Values.prometheusOperator.tls.internalPort }}
+ name: https
+ {{- else }}
+ ports:
+ - containerPort: 8080
+ name: http
+ {{- end }}
+ resources:
+{{ toYaml .Values.prometheusOperator.resources | indent 12 }}
+ securityContext:
+{{ toYaml .Values.prometheusOperator.containerSecurityContext | indent 12 }}
+{{- if .Values.prometheusOperator.tls.enabled }}
+ volumeMounts:
+ - name: tls-secret
+ mountPath: /cert
+ readOnly: true
+ volumes:
+ - name: tls-secret
+ secret:
+ defaultMode: 420
+ secretName: {{ template "kube-prometheus-stack.fullname" . }}-admission
+{{- end }}
+ {{- with .Values.prometheusOperator.dnsConfig }}
+ dnsConfig:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+{{- if .Values.prometheusOperator.securityContext }}
+ securityContext:
+{{ toYaml .Values.prometheusOperator.securityContext | indent 8 }}
+{{- end }}
+ serviceAccountName: {{ template "kube-prometheus-stack.operator.serviceAccountName" . }}
+{{- if .Values.prometheusOperator.hostNetwork }}
+ hostNetwork: true
+ dnsPolicy: ClusterFirstWithHostNet
+{{- end }}
+ {{- with .Values.prometheusOperator.nodeSelector }}
+ nodeSelector:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ {{- with .Values.prometheusOperator.affinity }}
+ affinity:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ {{- with .Values.prometheusOperator.tolerations }}
+ tolerations:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/psp-clusterrole.yaml b/kube-prometheus-stack/templates/prometheus-operator/psp-clusterrole.yaml
new file mode 100644
index 00000000..d667d627
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/psp-clusterrole.yaml
@@ -0,0 +1,20 @@
+{{- if and .Values.prometheusOperator.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }}
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-operator-psp
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+rules:
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if semverCompare "> 1.15.0-0" $kubeTargetVersion }}
+- apiGroups: ['policy']
+{{- else }}
+- apiGroups: ['extensions']
+{{- end }}
+ resources: ['podsecuritypolicies']
+ verbs: ['use']
+ resourceNames:
+ - {{ template "kube-prometheus-stack.fullname" . }}-operator
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/psp-clusterrolebinding.yaml b/kube-prometheus-stack/templates/prometheus-operator/psp-clusterrolebinding.yaml
new file mode 100644
index 00000000..c538cd17
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/psp-clusterrolebinding.yaml
@@ -0,0 +1,17 @@
+{{- if and .Values.prometheusOperator.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }}
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-operator-psp
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: {{ template "kube-prometheus-stack.fullname" . }}-operator-psp
+subjects:
+ - kind: ServiceAccount
+ name: {{ template "kube-prometheus-stack.operator.serviceAccountName" . }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/psp.yaml b/kube-prometheus-stack/templates/prometheus-operator/psp.yaml
new file mode 100644
index 00000000..d9228f0b
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/psp.yaml
@@ -0,0 +1,45 @@
+{{- if and .Values.prometheusOperator.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }}
+apiVersion: policy/v1beta1
+kind: PodSecurityPolicy
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-operator
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+{{- if .Values.global.rbac.pspAnnotations }}
+ annotations:
+{{ toYaml .Values.global.rbac.pspAnnotations | indent 4 }}
+{{- end }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ privileged: false
+ # Allow core volume types.
+ volumes:
+ - 'configMap'
+ - 'emptyDir'
+ - 'projected'
+ - 'secret'
+ - 'downwardAPI'
+ - 'persistentVolumeClaim'
+ hostNetwork: {{ .Values.prometheusOperator.hostNetwork }}
+ hostIPC: false
+ hostPID: false
+ runAsUser:
+ # Permits the container to run with root privileges as well.
+ rule: 'RunAsAny'
+ seLinux:
+ # This policy assumes the nodes are using AppArmor rather than SELinux.
+ rule: 'RunAsAny'
+ supplementalGroups:
+ rule: 'MustRunAs'
+ ranges:
+ # Allow adding the root group.
+ - min: 0
+ max: 65535
+ fsGroup:
+ rule: 'MustRunAs'
+ ranges:
+ # Allow adding the root group.
+ - min: 0
+ max: 65535
+ readOnlyRootFilesystem: false
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/service.yaml b/kube-prometheus-stack/templates/prometheus-operator/service.yaml
new file mode 100644
index 00000000..b5ef5b93
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/service.yaml
@@ -0,0 +1,58 @@
+{{- if .Values.prometheusOperator.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-operator
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.prometheusOperator.service.labels }}
+{{ toYaml .Values.prometheusOperator.service.labels | indent 4 }}
+{{- end }}
+{{- if .Values.prometheusOperator.service.annotations }}
+ annotations:
+{{ toYaml .Values.prometheusOperator.service.annotations | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.prometheusOperator.service.clusterIP }}
+ clusterIP: {{ .Values.prometheusOperator.service.clusterIP }}
+{{- end }}
+{{- if .Values.prometheusOperator.service.externalIPs }}
+ externalIPs:
+{{ toYaml .Values.prometheusOperator.service.externalIPs | indent 4 }}
+{{- end }}
+{{- if .Values.prometheusOperator.service.loadBalancerIP }}
+ loadBalancerIP: {{ .Values.prometheusOperator.service.loadBalancerIP }}
+{{- end }}
+{{- if .Values.prometheusOperator.service.loadBalancerSourceRanges }}
+ loadBalancerSourceRanges:
+ {{- range $cidr := .Values.prometheusOperator.service.loadBalancerSourceRanges }}
+ - {{ $cidr }}
+ {{- end }}
+{{- end }}
+{{- if ne .Values.prometheusOperator.service.type "ClusterIP" }}
+ externalTrafficPolicy: {{ .Values.prometheusOperator.service.externalTrafficPolicy }}
+{{- end }}
+ ports:
+ {{- if not .Values.prometheusOperator.tls.enabled }}
+ - name: http
+ {{- if eq .Values.prometheusOperator.service.type "NodePort" }}
+ nodePort: {{ .Values.prometheusOperator.service.nodePort }}
+ {{- end }}
+ port: 8080
+ targetPort: http
+ {{- end }}
+ {{- if .Values.prometheusOperator.tls.enabled }}
+ - name: https
+ {{- if eq .Values.prometheusOperator.service.type "NodePort"}}
+ nodePort: {{ .Values.prometheusOperator.service.nodePortTls }}
+ {{- end }}
+ port: 443
+ targetPort: https
+ {{- end }}
+ selector:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+ release: {{ $.Release.Name | quote }}
+ type: "{{ .Values.prometheusOperator.service.type }}"
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/serviceaccount.yaml b/kube-prometheus-stack/templates/prometheus-operator/serviceaccount.yaml
new file mode 100644
index 00000000..781975f3
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/serviceaccount.yaml
@@ -0,0 +1,16 @@
+{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.serviceAccount.create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ template "kube-prometheus-stack.operator.serviceAccountName" . }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+ app.kubernetes.io/name: {{ template "kube-prometheus-stack.name" . }}-prometheus-operator
+ app.kubernetes.io/component: prometheus-operator
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.global.imagePullSecrets }}
+imagePullSecrets:
+{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 2 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus-operator/servicemonitor.yaml b/kube-prometheus-stack/templates/prometheus-operator/servicemonitor.yaml
new file mode 100644
index 00000000..b7bd952b
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus-operator/servicemonitor.yaml
@@ -0,0 +1,44 @@
+{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.serviceMonitor.selfMonitor }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-operator
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ endpoints:
+ {{- if .Values.prometheusOperator.tls.enabled }}
+ - port: https
+ scheme: https
+ tlsConfig:
+ serverName: {{ template "kube-prometheus-stack.operator.fullname" . }}
+ ca:
+ secret:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-admission
+ key: {{ if .Values.prometheusOperator.admissionWebhooks.certManager.enabled }}ca.crt{{ else }}ca{{ end }}
+ optional: false
+ {{- else }}
+ - port: http
+ {{- end }}
+ honorLabels: true
+ {{- if .Values.prometheusOperator.serviceMonitor.interval }}
+ interval: {{ .Values.prometheusOperator.serviceMonitor.interval }}
+ {{- end }}
+{{- if .Values.prometheusOperator.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.prometheusOperator.serviceMonitor.metricRelabelings | indent 6) . }}
+{{- end }}
+{{- if .Values.prometheusOperator.serviceMonitor.relabelings }}
+ relabelings:
+{{ toYaml .Values.prometheusOperator.serviceMonitor.relabelings | indent 6 }}
+{{- end }}
+ selector:
+ matchLabels:
+ app: {{ template "kube-prometheus-stack.name" . }}-operator
+ release: {{ $.Release.Name | quote }}
+ namespaceSelector:
+ matchNames:
+ - {{ printf "%s" (include "kube-prometheus-stack.namespace" .) | quote }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/_rules.tpl b/kube-prometheus-stack/templates/prometheus/_rules.tpl
new file mode 100644
index 00000000..e8baf98e
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/_rules.tpl
@@ -0,0 +1,36 @@
+{{- /*
+Generated file. Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- define "rules.names" }}
+rules:
+ - "alertmanager.rules"
+ - "config-reloaders"
+ - "etcd"
+ - "general.rules"
+ - "k8s.rules"
+ - "kube-apiserver-availability.rules"
+ - "kube-apiserver-burnrate.rules"
+ - "kube-apiserver-histogram.rules"
+ - "kube-apiserver-slos"
+ - "kube-prometheus-general.rules"
+ - "kube-prometheus-node-recording.rules"
+ - "kube-scheduler.rules"
+ - "kube-state-metrics"
+ - "kubelet.rules"
+ - "kubernetes-apps"
+ - "kubernetes-resources"
+ - "kubernetes-storage"
+ - "kubernetes-system"
+ - "kubernetes-system-kube-proxy"
+ - "kubernetes-system-apiserver"
+ - "kubernetes-system-kubelet"
+ - "kubernetes-system-controller-manager"
+ - "kubernetes-system-scheduler"
+ - "node-exporter.rules"
+ - "node-exporter"
+ - "node.rules"
+ - "node-network"
+ - "prometheus-operator"
+ - "prometheus"
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/additionalAlertRelabelConfigs.yaml b/kube-prometheus-stack/templates/prometheus/additionalAlertRelabelConfigs.yaml
new file mode 100644
index 00000000..bff93098
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/additionalAlertRelabelConfigs.yaml
@@ -0,0 +1,16 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.prometheusSpec.additionalAlertRelabelConfigs }}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-am-relabel-confg
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- if .Values.prometheus.prometheusSpec.additionalPrometheusSecretsAnnotations }}
+ annotations:
+{{ toYaml .Values.prometheus.prometheusSpec.additionalPrometheusSecretsAnnotations | indent 4 }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus-am-relabel-confg
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+data:
+ additional-alert-relabel-configs.yaml: {{ toYaml .Values.prometheus.prometheusSpec.additionalAlertRelabelConfigs | b64enc | quote }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/additionalAlertmanagerConfigs.yaml b/kube-prometheus-stack/templates/prometheus/additionalAlertmanagerConfigs.yaml
new file mode 100644
index 00000000..2fe8fdb8
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/additionalAlertmanagerConfigs.yaml
@@ -0,0 +1,16 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.prometheusSpec.additionalAlertManagerConfigs }}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-am-confg
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- if .Values.prometheus.prometheusSpec.additionalPrometheusSecretsAnnotations }}
+ annotations:
+{{ toYaml .Values.prometheus.prometheusSpec.additionalPrometheusSecretsAnnotations | indent 4 }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus-am-confg
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+data:
+ additional-alertmanager-configs.yaml: {{ tpl (toYaml .Values.prometheus.prometheusSpec.additionalAlertManagerConfigs) . | b64enc | quote }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/additionalPrometheusRules.yaml b/kube-prometheus-stack/templates/prometheus/additionalPrometheusRules.yaml
new file mode 100644
index 00000000..cb4aabaa
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/additionalPrometheusRules.yaml
@@ -0,0 +1,43 @@
+{{- if or .Values.additionalPrometheusRules .Values.additionalPrometheusRulesMap}}
+apiVersion: v1
+kind: List
+metadata:
+ name: {{ include "kube-prometheus-stack.fullname" $ }}-additional-prometheus-rules
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+items:
+{{- if .Values.additionalPrometheusRulesMap }}
+{{- range $prometheusRuleName, $prometheusRule := .Values.additionalPrometheusRulesMap }}
+ - apiVersion: monitoring.coreos.com/v1
+ kind: PrometheusRule
+ metadata:
+ name: {{ template "kube-prometheus-stack.name" $ }}-{{ $prometheusRuleName }}
+ namespace: {{ template "kube-prometheus-stack.namespace" $ }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}
+{{ include "kube-prometheus-stack.labels" $ | indent 8 }}
+ {{- if $prometheusRule.additionalLabels }}
+{{ toYaml $prometheusRule.additionalLabels | indent 8 }}
+ {{- end }}
+ spec:
+ groups:
+{{ toYaml $prometheusRule.groups| indent 8 }}
+{{- end }}
+{{- else }}
+{{- range .Values.additionalPrometheusRules }}
+ - apiVersion: monitoring.coreos.com/v1
+ kind: PrometheusRule
+ metadata:
+ name: {{ template "kube-prometheus-stack.name" $ }}-{{ .name }}
+ namespace: {{ template "kube-prometheus-stack.namespace" $ }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}
+{{ include "kube-prometheus-stack.labels" $ | indent 8 }}
+ {{- if .additionalLabels }}
+{{ toYaml .additionalLabels | indent 8 }}
+ {{- end }}
+ spec:
+ groups:
+{{ toYaml .groups| indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/additionalScrapeConfigs.yaml b/kube-prometheus-stack/templates/prometheus/additionalScrapeConfigs.yaml
new file mode 100644
index 00000000..ebdf766f
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/additionalScrapeConfigs.yaml
@@ -0,0 +1,20 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.prometheusSpec.additionalScrapeConfigs }}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-scrape-confg
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- if .Values.prometheus.prometheusSpec.additionalPrometheusSecretsAnnotations }}
+ annotations:
+{{ toYaml .Values.prometheus.prometheusSpec.additionalPrometheusSecretsAnnotations | indent 4 }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus-scrape-confg
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+data:
+{{- if eq ( typeOf .Values.prometheus.prometheusSpec.additionalScrapeConfigs ) "string" }}
+ additional-scrape-configs.yaml: {{ tpl .Values.prometheus.prometheusSpec.additionalScrapeConfigs $ | b64enc | quote }}
+{{- else }}
+ additional-scrape-configs.yaml: {{ tpl (toYaml .Values.prometheus.prometheusSpec.additionalScrapeConfigs) $ | b64enc | quote }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/clusterrole.yaml b/kube-prometheus-stack/templates/prometheus/clusterrole.yaml
new file mode 100644
index 00000000..3585b5db
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/clusterrole.yaml
@@ -0,0 +1,30 @@
+{{- if and .Values.prometheus.enabled .Values.global.rbac.create }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+rules:
+# This permission are not in the kube-prometheus repo
+# they're grabbed from https://github.com/prometheus/prometheus/blob/master/documentation/examples/rbac-setup.yml
+- apiGroups: [""]
+ resources:
+ - nodes
+ - nodes/metrics
+ - services
+ - endpoints
+ - pods
+ verbs: ["get", "list", "watch"]
+- apiGroups:
+ - "networking.k8s.io"
+ resources:
+ - ingresses
+ verbs: ["get", "list", "watch"]
+- nonResourceURLs: ["/metrics", "/metrics/cadvisor"]
+ verbs: ["get"]
+{{- if .Values.prometheus.additionalRulesForClusterRole }}
+{{ toYaml .Values.prometheus.additionalRulesForClusterRole | indent 0 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/clusterrolebinding.yaml b/kube-prometheus-stack/templates/prometheus/clusterrolebinding.yaml
new file mode 100644
index 00000000..9fc4f65d
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/clusterrolebinding.yaml
@@ -0,0 +1,18 @@
+{{- if and .Values.prometheus.enabled .Values.global.rbac.create }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus
+subjects:
+ - kind: ServiceAccount
+ name: {{ template "kube-prometheus-stack.prometheus.serviceAccountName" . }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- end }}
+
diff --git a/kube-prometheus-stack/templates/prometheus/csi-secret.yaml b/kube-prometheus-stack/templates/prometheus/csi-secret.yaml
new file mode 100644
index 00000000..89399cec
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/csi-secret.yaml
@@ -0,0 +1,12 @@
+{{- if .Values.prometheus.prometheusSpec.thanos.secretProviderClass }}
+---
+apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
+kind: SecretProviderClass
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+spec:
+{{ toYaml .Values.prometheus.prometheusSpec.thanos.secretProviderClass | indent 2 }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/extrasecret.yaml b/kube-prometheus-stack/templates/prometheus/extrasecret.yaml
new file mode 100644
index 00000000..17f3478a
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/extrasecret.yaml
@@ -0,0 +1,20 @@
+{{- if .Values.prometheus.extraSecret.data -}}
+{{- $secretName := printf "prometheus-%s-extra" (include "kube-prometheus-stack.fullname" . ) -}}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ default $secretName .Values.prometheus.extraSecret.name }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- if .Values.prometheus.extraSecret.annotations }}
+ annotations:
+{{ toYaml .Values.prometheus.extraSecret.annotations | indent 4 }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+ app.kubernetes.io/component: prometheus
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+data:
+{{- range $key, $val := .Values.prometheus.extraSecret.data }}
+ {{ $key }}: {{ $val | b64enc | quote }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/ingress.yaml b/kube-prometheus-stack/templates/prometheus/ingress.yaml
new file mode 100644
index 00000000..91fadf90
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/ingress.yaml
@@ -0,0 +1,77 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.ingress.enabled -}}
+ {{- $pathType := .Values.prometheus.ingress.pathType | default "ImplementationSpecific" -}}
+ {{- $serviceName := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "prometheus" -}}
+ {{- $servicePort := .Values.prometheus.ingress.servicePort | default .Values.prometheus.service.port -}}
+ {{- $routePrefix := list .Values.prometheus.prometheusSpec.routePrefix -}}
+ {{- $paths := .Values.prometheus.ingress.paths | default $routePrefix -}}
+ {{- $apiIsStable := eq (include "kube-prometheus-stack.ingress.isStable" .) "true" -}}
+ {{- $ingressSupportsPathType := eq (include "kube-prometheus-stack.ingress.supportsPathType" .) "true" -}}
+apiVersion: {{ include "kube-prometheus-stack.ingress.apiVersion" . }}
+kind: Ingress
+metadata:
+{{- if .Values.prometheus.ingress.annotations }}
+ annotations:
+{{ toYaml .Values.prometheus.ingress.annotations | indent 4 }}
+{{- end }}
+ name: {{ $serviceName }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.prometheus.ingress.labels }}
+{{ toYaml .Values.prometheus.ingress.labels | indent 4 }}
+{{- end }}
+spec:
+ {{- if $apiIsStable }}
+ {{- if .Values.prometheus.ingress.ingressClassName }}
+ ingressClassName: {{ .Values.prometheus.ingress.ingressClassName }}
+ {{- end }}
+ {{- end }}
+ rules:
+ {{- if .Values.prometheus.ingress.hosts }}
+ {{- range $host := .Values.prometheus.ingress.hosts }}
+ - host: {{ tpl $host $ }}
+ http:
+ paths:
+ {{- range $p := $paths }}
+ - path: {{ tpl $p $ }}
+ {{- if and $pathType $ingressSupportsPathType }}
+ pathType: {{ $pathType }}
+ {{- end }}
+ backend:
+ {{- if $apiIsStable }}
+ service:
+ name: {{ $serviceName }}
+ port:
+ number: {{ $servicePort }}
+ {{- else }}
+ serviceName: {{ $serviceName }}
+ servicePort: {{ $servicePort }}
+ {{- end }}
+ {{- end -}}
+ {{- end -}}
+ {{- else }}
+ - http:
+ paths:
+ {{- range $p := $paths }}
+ - path: {{ tpl $p $ }}
+ {{- if and $pathType $ingressSupportsPathType }}
+ pathType: {{ $pathType }}
+ {{- end }}
+ backend:
+ {{- if $apiIsStable }}
+ service:
+ name: {{ $serviceName }}
+ port:
+ number: {{ $servicePort }}
+ {{- else }}
+ serviceName: {{ $serviceName }}
+ servicePort: {{ $servicePort }}
+ {{- end }}
+ {{- end -}}
+ {{- end -}}
+ {{- if .Values.prometheus.ingress.tls }}
+ tls:
+{{ tpl (toYaml .Values.prometheus.ingress.tls | indent 4) . }}
+ {{- end -}}
+{{- end -}}
diff --git a/kube-prometheus-stack/templates/prometheus/ingressThanosSidecar.yaml b/kube-prometheus-stack/templates/prometheus/ingressThanosSidecar.yaml
new file mode 100644
index 00000000..7a338597
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/ingressThanosSidecar.yaml
@@ -0,0 +1,76 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.thanosIngress.enabled }}
+{{- $pathType := .Values.prometheus.thanosIngress.pathType | default "" }}
+{{- $serviceName := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "prometheus" }}
+{{- $thanosPort := .Values.prometheus.thanosIngress.servicePort -}}
+{{- $routePrefix := list .Values.prometheus.prometheusSpec.routePrefix }}
+{{- $paths := .Values.prometheus.thanosIngress.paths | default $routePrefix -}}
+{{- $apiIsStable := eq (include "kube-prometheus-stack.ingress.isStable" .) "true" -}}
+{{- $ingressSupportsPathType := eq (include "kube-prometheus-stack.ingress.supportsPathType" .) "true" -}}
+apiVersion: {{ include "kube-prometheus-stack.ingress.apiVersion" . }}
+kind: Ingress
+metadata:
+{{- if .Values.prometheus.thanosIngress.annotations }}
+ annotations:
+{{ toYaml .Values.prometheus.thanosIngress.annotations | indent 4 }}
+{{- end }}
+ name: {{ template "kube-prometheus-stack.fullname" . }}-thanos-gateway
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.prometheus.thanosIngress.labels }}
+{{ toYaml .Values.prometheus.thanosIngress.labels | indent 4 }}
+{{- end }}
+spec:
+ {{- if $apiIsStable }}
+ {{- if .Values.prometheus.thanosIngress.ingressClassName }}
+ ingressClassName: {{ .Values.prometheus.thanosIngress.ingressClassName }}
+ {{- end }}
+ {{- end }}
+ rules:
+ {{- if .Values.prometheus.thanosIngress.hosts }}
+ {{- range $host := .Values.prometheus.thanosIngress.hosts }}
+ - host: {{ tpl $host $ }}
+ http:
+ paths:
+ {{- range $p := $paths }}
+ - path: {{ tpl $p $ }}
+ {{- if and $pathType $ingressSupportsPathType }}
+ pathType: {{ $pathType }}
+ {{- end }}
+ backend:
+ {{- if $apiIsStable }}
+ service:
+ name: {{ $serviceName }}
+ port:
+ number: {{ $thanosPort }}
+ {{- else }}
+ serviceName: {{ $serviceName }}
+ servicePort: {{ $thanosPort }}
+ {{- end }}
+ {{- end -}}
+ {{- end -}}
+ {{- else }}
+ - http:
+ paths:
+ {{- range $p := $paths }}
+ - path: {{ tpl $p $ }}
+ {{- if and $pathType $ingressSupportsPathType }}
+ pathType: {{ $pathType }}
+ {{- end }}
+ backend:
+ {{- if $apiIsStable }}
+ service:
+ name: {{ $serviceName }}
+ port:
+ number: {{ $thanosPort }}
+ {{- else }}
+ serviceName: {{ $serviceName }}
+ servicePort: {{ $thanosPort }}
+ {{- end }}
+ {{- end -}}
+ {{- end -}}
+ {{- if .Values.prometheus.thanosIngress.tls }}
+ tls:
+{{ tpl (toYaml .Values.prometheus.thanosIngress.tls | indent 4) . }}
+ {{- end -}}
+{{- end -}}
diff --git a/kube-prometheus-stack/templates/prometheus/ingressperreplica.yaml b/kube-prometheus-stack/templates/prometheus/ingressperreplica.yaml
new file mode 100644
index 00000000..df631993
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/ingressperreplica.yaml
@@ -0,0 +1,67 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.servicePerReplica.enabled .Values.prometheus.ingressPerReplica.enabled }}
+{{- $pathType := .Values.prometheus.ingressPerReplica.pathType | default "" }}
+{{- $count := .Values.prometheus.prometheusSpec.replicas | int -}}
+{{- $servicePort := .Values.prometheus.servicePerReplica.port -}}
+{{- $ingressValues := .Values.prometheus.ingressPerReplica -}}
+{{- $apiIsStable := eq (include "kube-prometheus-stack.ingress.isStable" .) "true" -}}
+{{- $ingressSupportsPathType := eq (include "kube-prometheus-stack.ingress.supportsPathType" .) "true" -}}
+apiVersion: v1
+kind: List
+metadata:
+ name: {{ include "kube-prometheus-stack.fullname" $ }}-prometheus-ingressperreplica
+ namespace: {{ template "kube-prometheus-stack.namespace" $ }}
+items:
+{{ range $i, $e := until $count }}
+ - kind: Ingress
+ apiVersion: {{ include "kube-prometheus-stack.ingress.apiVersion" $ }}
+ metadata:
+ name: {{ include "kube-prometheus-stack.fullname" $ }}-prometheus-{{ $i }}
+ namespace: {{ template "kube-prometheus-stack.namespace" $ }}
+ labels:
+ app: {{ include "kube-prometheus-stack.name" $ }}-prometheus
+ {{ include "kube-prometheus-stack.labels" $ | indent 8 }}
+ {{- if $ingressValues.labels }}
+{{ toYaml $ingressValues.labels | indent 8 }}
+ {{- end }}
+ {{- if $ingressValues.annotations }}
+ annotations:
+{{ toYaml $ingressValues.annotations | indent 8 }}
+ {{- end }}
+ spec:
+ {{- if $apiIsStable }}
+ {{- if $ingressValues.ingressClassName }}
+ ingressClassName: {{ $ingressValues.ingressClassName }}
+ {{- end }}
+ {{- end }}
+ rules:
+ - host: {{ $ingressValues.hostPrefix }}-{{ $i }}.{{ $ingressValues.hostDomain }}
+ http:
+ paths:
+ {{- range $p := $ingressValues.paths }}
+ - path: {{ tpl $p $ }}
+ {{- if and $pathType $ingressSupportsPathType }}
+ pathType: {{ $pathType }}
+ {{- end }}
+ backend:
+ {{- if $apiIsStable }}
+ service:
+ name: {{ include "kube-prometheus-stack.fullname" $ }}-prometheus-{{ $i }}
+ port:
+ number: {{ $servicePort }}
+ {{- else }}
+ serviceName: {{ include "kube-prometheus-stack.fullname" $ }}-prometheus-{{ $i }}
+ servicePort: {{ $servicePort }}
+ {{- end }}
+ {{- end -}}
+ {{- if or $ingressValues.tlsSecretName $ingressValues.tlsSecretPerReplica.enabled }}
+ tls:
+ - hosts:
+ - {{ $ingressValues.hostPrefix }}-{{ $i }}.{{ $ingressValues.hostDomain }}
+ {{- if $ingressValues.tlsSecretPerReplica.enabled }}
+ secretName: {{ $ingressValues.tlsSecretPerReplica.prefix }}-{{ $i }}
+ {{- else }}
+ secretName: {{ $ingressValues.tlsSecretName }}
+ {{- end }}
+ {{- end }}
+{{- end -}}
+{{- end -}}
diff --git a/kube-prometheus-stack/templates/prometheus/podDisruptionBudget.yaml b/kube-prometheus-stack/templates/prometheus/podDisruptionBudget.yaml
new file mode 100644
index 00000000..02a320ef
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/podDisruptionBudget.yaml
@@ -0,0 +1,21 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.podDisruptionBudget.enabled }}
+apiVersion: {{ include "kube-prometheus-stack.pdb.apiVersion" . }}
+kind: PodDisruptionBudget
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ {{- if .Values.prometheus.podDisruptionBudget.minAvailable }}
+ minAvailable: {{ .Values.prometheus.podDisruptionBudget.minAvailable }}
+ {{- end }}
+ {{- if .Values.prometheus.podDisruptionBudget.maxUnavailable }}
+ maxUnavailable: {{ .Values.prometheus.podDisruptionBudget.maxUnavailable }}
+ {{- end }}
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: prometheus
+ prometheus: {{ template "kube-prometheus-stack.prometheus.crname" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/podmonitors.yaml b/kube-prometheus-stack/templates/prometheus/podmonitors.yaml
new file mode 100644
index 00000000..95d568e1
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/podmonitors.yaml
@@ -0,0 +1,37 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.additionalPodMonitors }}
+apiVersion: v1
+kind: List
+items:
+{{- range .Values.prometheus.additionalPodMonitors }}
+ - apiVersion: monitoring.coreos.com/v1
+ kind: PodMonitor
+ metadata:
+ name: {{ .name }}
+ namespace: {{ template "kube-prometheus-stack.namespace" $ }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-prometheus
+{{ include "kube-prometheus-stack.labels" $ | indent 8 }}
+ {{- if .additionalLabels }}
+{{ toYaml .additionalLabels | indent 8 }}
+ {{- end }}
+ spec:
+ podMetricsEndpoints:
+{{ toYaml .podMetricsEndpoints | indent 8 }}
+ {{- if .jobLabel }}
+ jobLabel: {{ .jobLabel }}
+ {{- end }}
+ {{- if .namespaceSelector }}
+ namespaceSelector:
+{{ toYaml .namespaceSelector | indent 8 }}
+ {{- end }}
+ selector:
+{{ toYaml .selector | indent 8 }}
+ {{- if .podTargetLabels }}
+ podTargetLabels:
+{{ toYaml .podTargetLabels | indent 8 }}
+ {{- end }}
+ {{- if .sampleLimit }}
+ sampleLimit: {{ .sampleLimit }}
+ {{- end }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/prometheus.yaml b/kube-prometheus-stack/templates/prometheus/prometheus.yaml
new file mode 100644
index 00000000..2c532d7a
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/prometheus.yaml
@@ -0,0 +1,386 @@
+{{- if .Values.prometheus.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: Prometheus
+metadata:
+ name: {{ template "kube-prometheus-stack.prometheus.crname" . }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.prometheus.annotations }}
+ annotations:
+{{ toYaml .Values.prometheus.annotations | indent 4 }}
+{{- end }}
+spec:
+ alerting:
+ alertmanagers:
+{{- if .Values.prometheus.prometheusSpec.alertingEndpoints }}
+{{ toYaml .Values.prometheus.prometheusSpec.alertingEndpoints | indent 6 }}
+{{- else if .Values.alertmanager.enabled }}
+ - namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager
+ port: {{ .Values.alertmanager.alertmanagerSpec.portName }}
+ {{- if .Values.alertmanager.alertmanagerSpec.routePrefix }}
+ pathPrefix: "{{ .Values.alertmanager.alertmanagerSpec.routePrefix }}"
+ {{- end }}
+ apiVersion: {{ .Values.alertmanager.apiVersion }}
+{{- else }}
+ []
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.apiserverConfig }}
+ apiserverConfig:
+{{ toYaml .Values.prometheus.prometheusSpec.apiserverConfig | indent 4}}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.image }}
+ {{- if and .Values.prometheus.prometheusSpec.image.tag .Values.prometheus.prometheusSpec.image.sha }}
+ image: "{{ .Values.prometheus.prometheusSpec.image.repository }}:{{ .Values.prometheus.prometheusSpec.image.tag }}@sha256:{{ .Values.prometheus.prometheusSpec.image.sha }}"
+ {{- else if .Values.prometheus.prometheusSpec.image.sha }}
+ image: "{{ .Values.prometheus.prometheusSpec.image.repository }}@sha256:{{ .Values.prometheus.prometheusSpec.image.sha }}"
+ {{- else if .Values.prometheus.prometheusSpec.image.tag }}
+ image: "{{ .Values.prometheus.prometheusSpec.image.repository }}:{{ .Values.prometheus.prometheusSpec.image.tag }}"
+ {{- else }}
+ image: "{{ .Values.prometheus.prometheusSpec.image.repository }}"
+ {{- end }}
+ version: {{ .Values.prometheus.prometheusSpec.image.tag }}
+ {{- if .Values.prometheus.prometheusSpec.image.sha }}
+ sha: {{ .Values.prometheus.prometheusSpec.image.sha }}
+ {{- end }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.externalLabels }}
+ externalLabels:
+{{ tpl (toYaml .Values.prometheus.prometheusSpec.externalLabels | indent 4) . }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.prometheusExternalLabelNameClear }}
+ prometheusExternalLabelName: ""
+{{- else if .Values.prometheus.prometheusSpec.prometheusExternalLabelName }}
+ prometheusExternalLabelName: "{{ .Values.prometheus.prometheusSpec.prometheusExternalLabelName }}"
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.replicaExternalLabelNameClear }}
+ replicaExternalLabelName: ""
+{{- else if .Values.prometheus.prometheusSpec.replicaExternalLabelName }}
+ replicaExternalLabelName: "{{ .Values.prometheus.prometheusSpec.replicaExternalLabelName }}"
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.enableRemoteWriteReceiver }}
+ enableRemoteWriteReceiver: {{ .Values.prometheus.prometheusSpec.enableRemoteWriteReceiver }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.externalUrl }}
+ externalUrl: "{{ tpl .Values.prometheus.prometheusSpec.externalUrl . }}"
+{{- else if and .Values.prometheus.ingress.enabled .Values.prometheus.ingress.hosts }}
+ externalUrl: "http://{{ tpl (index .Values.prometheus.ingress.hosts 0) . }}{{ .Values.prometheus.prometheusSpec.routePrefix }}"
+{{- else }}
+ externalUrl: http://{{ template "kube-prometheus-stack.fullname" . }}-prometheus.{{ template "kube-prometheus-stack.namespace" . }}:{{ .Values.prometheus.service.port }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.nodeSelector }}
+ nodeSelector:
+{{ toYaml .Values.prometheus.prometheusSpec.nodeSelector | indent 4 }}
+{{- end }}
+ paused: {{ .Values.prometheus.prometheusSpec.paused }}
+ replicas: {{ .Values.prometheus.prometheusSpec.replicas }}
+ shards: {{ .Values.prometheus.prometheusSpec.shards }}
+ logLevel: {{ .Values.prometheus.prometheusSpec.logLevel }}
+ logFormat: {{ .Values.prometheus.prometheusSpec.logFormat }}
+ listenLocal: {{ .Values.prometheus.prometheusSpec.listenLocal }}
+ enableAdminAPI: {{ .Values.prometheus.prometheusSpec.enableAdminAPI }}
+{{- if .Values.prometheus.prometheusSpec.web }}
+ web:
+{{ toYaml .Values.prometheus.prometheusSpec.web | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.exemplars }}
+ exemplars:
+ {{ toYaml .Values.prometheus.prometheusSpec.exemplars | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.enableFeatures }}
+ enableFeatures:
+{{- range $enableFeatures := .Values.prometheus.prometheusSpec.enableFeatures }}
+ - {{ tpl $enableFeatures $ }}
+{{- end }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.scrapeInterval }}
+ scrapeInterval: {{ .Values.prometheus.prometheusSpec.scrapeInterval }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.scrapeTimeout }}
+ scrapeTimeout: {{ .Values.prometheus.prometheusSpec.scrapeTimeout }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.evaluationInterval }}
+ evaluationInterval: {{ .Values.prometheus.prometheusSpec.evaluationInterval }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.resources }}
+ resources:
+{{ toYaml .Values.prometheus.prometheusSpec.resources | indent 4 }}
+{{- end }}
+ retention: {{ .Values.prometheus.prometheusSpec.retention | quote }}
+{{- if .Values.prometheus.prometheusSpec.retentionSize }}
+ retentionSize: {{ .Values.prometheus.prometheusSpec.retentionSize | quote }}
+{{- end }}
+{{- if eq .Values.prometheus.prometheusSpec.walCompression false }}
+ walCompression: false
+{{ else }}
+ walCompression: true
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.routePrefix }}
+ routePrefix: {{ .Values.prometheus.prometheusSpec.routePrefix | quote }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.secrets }}
+ secrets:
+{{ toYaml .Values.prometheus.prometheusSpec.secrets | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.configMaps }}
+ configMaps:
+{{ toYaml .Values.prometheus.prometheusSpec.configMaps | indent 4 }}
+{{- end }}
+ serviceAccountName: {{ template "kube-prometheus-stack.prometheus.serviceAccountName" . }}
+{{- if .Values.prometheus.prometheusSpec.serviceMonitorSelector }}
+ serviceMonitorSelector:
+{{ toYaml .Values.prometheus.prometheusSpec.serviceMonitorSelector | indent 4 }}
+{{ else if .Values.prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues }}
+ serviceMonitorSelector:
+ matchLabels:
+ release: {{ $.Release.Name | quote }}
+{{ else }}
+ serviceMonitorSelector: {}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.serviceMonitorNamespaceSelector }}
+ serviceMonitorNamespaceSelector:
+{{ toYaml .Values.prometheus.prometheusSpec.serviceMonitorNamespaceSelector | indent 4 }}
+{{ else }}
+ serviceMonitorNamespaceSelector: {}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.podMonitorSelector }}
+ podMonitorSelector:
+{{ toYaml .Values.prometheus.prometheusSpec.podMonitorSelector | indent 4 }}
+{{ else if .Values.prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues }}
+ podMonitorSelector:
+ matchLabels:
+ release: {{ $.Release.Name | quote }}
+{{ else }}
+ podMonitorSelector: {}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.podMonitorNamespaceSelector }}
+ podMonitorNamespaceSelector:
+{{ toYaml .Values.prometheus.prometheusSpec.podMonitorNamespaceSelector | indent 4 }}
+{{ else }}
+ podMonitorNamespaceSelector: {}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.probeSelector }}
+ probeSelector:
+{{ toYaml .Values.prometheus.prometheusSpec.probeSelector | indent 4 }}
+{{ else if .Values.prometheus.prometheusSpec.probeSelectorNilUsesHelmValues }}
+ probeSelector:
+ matchLabels:
+ release: {{ $.Release.Name | quote }}
+{{ else }}
+ probeSelector: {}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.probeNamespaceSelector }}
+ probeNamespaceSelector:
+{{ toYaml .Values.prometheus.prometheusSpec.probeNamespaceSelector | indent 4 }}
+{{ else }}
+ probeNamespaceSelector: {}
+{{- end }}
+{{- if (or .Values.prometheus.prometheusSpec.remoteRead .Values.prometheus.prometheusSpec.additionalRemoteRead) }}
+ remoteRead:
+{{- if .Values.prometheus.prometheusSpec.remoteRead }}
+{{ tpl (toYaml .Values.prometheus.prometheusSpec.remoteRead | indent 4) . }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.additionalRemoteRead }}
+{{ toYaml .Values.prometheus.prometheusSpec.additionalRemoteRead | indent 4 }}
+{{- end }}
+{{- end }}
+{{- if (or .Values.prometheus.prometheusSpec.remoteWrite .Values.prometheus.prometheusSpec.additionalRemoteWrite) }}
+ remoteWrite:
+{{- if .Values.prometheus.prometheusSpec.remoteWrite }}
+{{ tpl (toYaml .Values.prometheus.prometheusSpec.remoteWrite | indent 4) . }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.additionalRemoteWrite }}
+{{ toYaml .Values.prometheus.prometheusSpec.additionalRemoteWrite | indent 4 }}
+{{- end }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.securityContext }}
+ securityContext:
+{{ toYaml .Values.prometheus.prometheusSpec.securityContext | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.ruleNamespaceSelector }}
+ ruleNamespaceSelector:
+{{ toYaml .Values.prometheus.prometheusSpec.ruleNamespaceSelector | indent 4 }}
+{{ else }}
+ ruleNamespaceSelector: {}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.ruleSelector }}
+ ruleSelector:
+{{ toYaml .Values.prometheus.prometheusSpec.ruleSelector | indent 4}}
+{{- else if .Values.prometheus.prometheusSpec.ruleSelectorNilUsesHelmValues }}
+ ruleSelector:
+ matchLabels:
+ release: {{ $.Release.Name | quote }}
+{{ else }}
+ ruleSelector: {}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.storageSpec }}
+ storage:
+{{ tpl (toYaml .Values.prometheus.prometheusSpec.storageSpec | indent 4) . }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.podMetadata }}
+ podMetadata:
+{{ tpl (toYaml .Values.prometheus.prometheusSpec.podMetadata | indent 4) . }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.query }}
+ query:
+{{ toYaml .Values.prometheus.prometheusSpec.query | indent 4}}
+{{- end }}
+{{- if or .Values.prometheus.prometheusSpec.podAntiAffinity .Values.prometheus.prometheusSpec.affinity }}
+ affinity:
+{{- if .Values.prometheus.prometheusSpec.affinity }}
+{{ toYaml .Values.prometheus.prometheusSpec.affinity | indent 4 }}
+{{- end }}
+{{- if eq .Values.prometheus.prometheusSpec.podAntiAffinity "hard" }}
+ podAntiAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ - topologyKey: {{ .Values.prometheus.prometheusSpec.podAntiAffinityTopologyKey }}
+ labelSelector:
+ matchExpressions:
+ - {key: app.kubernetes.io/name, operator: In, values: [prometheus]}
+ - {key: prometheus, operator: In, values: [{{ template "kube-prometheus-stack.fullname" . }}-prometheus]}
+{{- else if eq .Values.prometheus.prometheusSpec.podAntiAffinity "soft" }}
+ podAntiAffinity:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ - weight: 100
+ podAffinityTerm:
+ topologyKey: {{ .Values.prometheus.prometheusSpec.podAntiAffinityTopologyKey }}
+ labelSelector:
+ matchExpressions:
+ - {key: app.kubernetes.io/name, operator: In, values: [prometheus]}
+ - {key: prometheus, operator: In, values: [{{ template "kube-prometheus-stack.fullname" . }}-prometheus]}
+{{- end }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.tolerations }}
+ tolerations:
+{{ toYaml .Values.prometheus.prometheusSpec.tolerations | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.topologySpreadConstraints }}
+ topologySpreadConstraints:
+{{ toYaml .Values.prometheus.prometheusSpec.topologySpreadConstraints | indent 4 }}
+{{- end }}
+{{- if .Values.global.imagePullSecrets }}
+ imagePullSecrets:
+{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.additionalScrapeConfigs }}
+ additionalScrapeConfigs:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-scrape-confg
+ key: additional-scrape-configs.yaml
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.additionalScrapeConfigsSecret.enabled }}
+ additionalScrapeConfigs:
+ name: {{ .Values.prometheus.prometheusSpec.additionalScrapeConfigsSecret.name }}
+ key: {{ .Values.prometheus.prometheusSpec.additionalScrapeConfigsSecret.key }}
+{{- end }}
+{{- if or .Values.prometheus.prometheusSpec.additionalAlertManagerConfigs .Values.prometheus.prometheusSpec.additionalAlertManagerConfigsSecret }}
+ additionalAlertManagerConfigs:
+{{- if .Values.prometheus.prometheusSpec.additionalAlertManagerConfigs }}
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-am-confg
+ key: additional-alertmanager-configs.yaml
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.additionalAlertManagerConfigsSecret }}
+ name: {{ .Values.prometheus.prometheusSpec.additionalAlertManagerConfigsSecret.name }}
+ key: {{ .Values.prometheus.prometheusSpec.additionalAlertManagerConfigsSecret.key }}
+ {{- if hasKey .Values.prometheus.prometheusSpec.additionalAlertManagerConfigsSecret "optional" }}
+ optional: {{ .Values.prometheus.prometheusSpec.additionalAlertManagerConfigsSecret.optional }}
+ {{- end }}
+{{- end }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.additionalAlertRelabelConfigs }}
+ additionalAlertRelabelConfigs:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-am-relabel-confg
+ key: additional-alert-relabel-configs.yaml
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.additionalAlertRelabelConfigsSecret }}
+ additionalAlertRelabelConfigs:
+ name: {{ .Values.prometheus.prometheusSpec.additionalAlertRelabelConfigsSecret.name }}
+ key: {{ .Values.prometheus.prometheusSpec.additionalAlertRelabelConfigsSecret.key }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.containers }}
+ containers:
+{{ toYaml .Values.prometheus.prometheusSpec.containers | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.initContainers }}
+ initContainers:
+{{ toYaml .Values.prometheus.prometheusSpec.initContainers | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.priorityClassName }}
+ priorityClassName: {{ .Values.prometheus.prometheusSpec.priorityClassName }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.thanos }}
+ thanos:
+{{ toYaml .Values.prometheus.prometheusSpec.thanos | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.disableCompaction }}
+ disableCompaction: {{ .Values.prometheus.prometheusSpec.disableCompaction }}
+{{- end }}
+ portName: {{ .Values.prometheus.prometheusSpec.portName }}
+{{- if .Values.prometheus.prometheusSpec.volumes }}
+ volumes:
+{{ toYaml .Values.prometheus.prometheusSpec.volumes | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.volumeMounts }}
+ volumeMounts:
+{{ toYaml .Values.prometheus.prometheusSpec.volumeMounts | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.arbitraryFSAccessThroughSMs }}
+ arbitraryFSAccessThroughSMs:
+{{ toYaml .Values.prometheus.prometheusSpec.arbitraryFSAccessThroughSMs | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.overrideHonorLabels }}
+ overrideHonorLabels: {{ .Values.prometheus.prometheusSpec.overrideHonorLabels }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.overrideHonorTimestamps }}
+ overrideHonorTimestamps: {{ .Values.prometheus.prometheusSpec.overrideHonorTimestamps }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.ignoreNamespaceSelectors }}
+ ignoreNamespaceSelectors: {{ .Values.prometheus.prometheusSpec.ignoreNamespaceSelectors }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.enforcedNamespaceLabel }}
+ enforcedNamespaceLabel: {{ .Values.prometheus.prometheusSpec.enforcedNamespaceLabel }}
+{{- $prometheusDefaultRulesExcludedFromEnforce := (include "rules.names" .) | fromYaml }}
+ prometheusRulesExcludedFromEnforce:
+{{- range $prometheusDefaultRulesExcludedFromEnforce.rules }}
+ - ruleNamespace: "{{ template "kube-prometheus-stack.namespace" $ }}"
+ ruleName: "{{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) . | trunc 63 | trimSuffix "-" }}"
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.prometheusRulesExcludedFromEnforce }}
+{{ toYaml .Values.prometheus.prometheusSpec.prometheusRulesExcludedFromEnforce | indent 4 }}
+{{- end }}
+ excludedFromEnforcement:
+{{- range $prometheusDefaultRulesExcludedFromEnforce.rules }}
+ - resource: prometheusrules
+ namespace: "{{ template "kube-prometheus-stack.namespace" $ }}"
+ name: "{{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) . | trunc 63 | trimSuffix "-" }}"
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.excludedFromEnforcement }}
+{{ tpl (toYaml .Values.prometheus.prometheusSpec.excludedFromEnforcement | indent 4) . }}
+{{- end }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.queryLogFile }}
+ queryLogFile: {{ .Values.prometheus.prometheusSpec.queryLogFile }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.enforcedSampleLimit }}
+ enforcedSampleLimit: {{ .Values.prometheus.prometheusSpec.enforcedSampleLimit }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.enforcedTargetLimit }}
+ enforcedTargetLimit: {{ .Values.prometheus.prometheusSpec.enforcedTargetLimit }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.enforcedLabelLimit }}
+ enforcedLabelLimit: {{ .Values.prometheus.prometheusSpec.enforcedLabelLimit }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.enforcedLabelNameLengthLimit }}
+ enforcedLabelNameLengthLimit: {{ .Values.prometheus.prometheusSpec.enforcedLabelNameLengthLimit }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.enforcedLabelValueLengthLimit}}
+ enforcedLabelValueLengthLimit: {{ .Values.prometheus.prometheusSpec.enforcedLabelValueLengthLimit }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.allowOverlappingBlocks }}
+ allowOverlappingBlocks: {{ .Values.prometheus.prometheusSpec.allowOverlappingBlocks }}
+{{- end }}
+{{- if .Values.prometheus.prometheusSpec.minReadySeconds }}
+ minReadySeconds: {{ .Values.prometheus.prometheusSpec.minReadySeconds }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/psp-clusterrole.yaml b/kube-prometheus-stack/templates/prometheus/psp-clusterrole.yaml
new file mode 100644
index 00000000..a279fb24
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/psp-clusterrole.yaml
@@ -0,0 +1,20 @@
+{{- if and .Values.prometheus.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }}
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-psp
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+rules:
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if semverCompare "> 1.15.0-0" $kubeTargetVersion }}
+- apiGroups: ['policy']
+{{- else }}
+- apiGroups: ['extensions']
+{{- end }}
+ resources: ['podsecuritypolicies']
+ verbs: ['use']
+ resourceNames:
+ - {{ template "kube-prometheus-stack.fullname" . }}-prometheus
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/psp-clusterrolebinding.yaml b/kube-prometheus-stack/templates/prometheus/psp-clusterrolebinding.yaml
new file mode 100644
index 00000000..27b73b74
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/psp-clusterrolebinding.yaml
@@ -0,0 +1,18 @@
+{{- if and .Values.prometheus.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-psp
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-psp
+subjects:
+ - kind: ServiceAccount
+ name: {{ template "kube-prometheus-stack.prometheus.serviceAccountName" . }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- end }}
+
diff --git a/kube-prometheus-stack/templates/prometheus/psp.yaml b/kube-prometheus-stack/templates/prometheus/psp.yaml
new file mode 100644
index 00000000..eecf9928
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/psp.yaml
@@ -0,0 +1,56 @@
+{{- if and .Values.prometheus.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }}
+apiVersion: policy/v1beta1
+kind: PodSecurityPolicy
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+{{- if .Values.global.rbac.pspAnnotations }}
+ annotations:
+{{ toYaml .Values.global.rbac.pspAnnotations | indent 4 }}
+{{- end }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ privileged: false
+ # Allow core volume types.
+ volumes:
+ - 'configMap'
+ - 'emptyDir'
+ - 'projected'
+ - 'secret'
+ - 'downwardAPI'
+ - 'persistentVolumeClaim'
+{{- if .Values.prometheus.podSecurityPolicy.volumes }}
+{{ toYaml .Values.prometheus.podSecurityPolicy.volumes | indent 4 }}
+{{- end }}
+ hostNetwork: false
+ hostIPC: false
+ hostPID: false
+ runAsUser:
+ # Permits the container to run with root privileges as well.
+ rule: 'RunAsAny'
+ seLinux:
+ # This policy assumes the nodes are using AppArmor rather than SELinux.
+ rule: 'RunAsAny'
+ supplementalGroups:
+ rule: 'MustRunAs'
+ ranges:
+ # Allow adding the root group.
+ - min: 0
+ max: 65535
+ fsGroup:
+ rule: 'MustRunAs'
+ ranges:
+ # Allow adding the root group.
+ - min: 0
+ max: 65535
+ readOnlyRootFilesystem: false
+{{- if .Values.prometheus.podSecurityPolicy.allowedCapabilities }}
+ allowedCapabilities:
+{{ toYaml .Values.prometheus.podSecurityPolicy.allowedCapabilities | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.podSecurityPolicy.allowedHostPaths }}
+ allowedHostPaths:
+{{ toYaml .Values.prometheus.podSecurityPolicy.allowedHostPaths | indent 4 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/alertmanager.rules.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/alertmanager.rules.yaml
new file mode 100644
index 00000000..f2fcc1ca
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/alertmanager.rules.yaml
@@ -0,0 +1,215 @@
+{{- /*
+Generated from 'alertmanager.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/alertmanager-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.alertmanager }}
+{{- $alertmanagerJob := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "alertmanager" }}
+{{- $namespace := printf "%s" (include "kube-prometheus-stack.namespace" .) }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "alertmanager.rules" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: alertmanager.rules
+ rules:
+{{- if not (.Values.defaultRules.disabled.AlertmanagerFailedReload | default false) }}
+ - alert: AlertmanagerFailedReload
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Configuration has failed to load for {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.pod{{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerfailedreload
+ summary: Reloading an Alertmanager configuration has failed.
+ expr: |-
+ # Without max_over_time, failed scrapes could create false negatives, see
+ # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details.
+ max_over_time(alertmanager_config_last_reload_successful{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[5m]) == 0
+ for: 10m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.AlertmanagerMembersInconsistent | default false) }}
+ - alert: AlertmanagerMembersInconsistent
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Alertmanager {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.pod{{`}}`}} has only found {{`{{`}} $value {{`}}`}} members of the {{`{{`}}$labels.job{{`}}`}} cluster.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagermembersinconsistent
+ summary: A member of an Alertmanager cluster has not found all other cluster members.
+ expr: |-
+ # Without max_over_time, failed scrapes could create false negatives, see
+ # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details.
+ max_over_time(alertmanager_cluster_members{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[5m])
+ < on (namespace,service) group_left
+ count by (namespace,service) (max_over_time(alertmanager_cluster_members{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[5m]))
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.AlertmanagerFailedToSendAlerts | default false) }}
+ - alert: AlertmanagerFailedToSendAlerts
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Alertmanager {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.pod{{`}}`}} failed to send {{`{{`}} $value | humanizePercentage {{`}}`}} of notifications to {{`{{`}} $labels.integration {{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerfailedtosendalerts
+ summary: An Alertmanager instance failed to send notifications.
+ expr: |-
+ (
+ rate(alertmanager_notifications_failed_total{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[5m])
+ /
+ rate(alertmanager_notifications_total{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[5m])
+ )
+ > 0.01
+ for: 5m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.AlertmanagerClusterFailedToSendAlerts | default false) }}
+ - alert: AlertmanagerClusterFailedToSendAlerts
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: The minimum notification failure rate to {{`{{`}} $labels.integration {{`}}`}} sent from any instance in the {{`{{`}}$labels.job{{`}}`}} cluster is {{`{{`}} $value | humanizePercentage {{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerclusterfailedtosendalerts
+ summary: All Alertmanager instances in a cluster failed to send notifications to a critical integration.
+ expr: |-
+ min by (namespace,service, integration) (
+ rate(alertmanager_notifications_failed_total{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}", integration=~`.*`}[5m])
+ /
+ rate(alertmanager_notifications_total{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}", integration=~`.*`}[5m])
+ )
+ > 0.01
+ for: 5m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.AlertmanagerClusterFailedToSendAlerts | default false) }}
+ - alert: AlertmanagerClusterFailedToSendAlerts
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: The minimum notification failure rate to {{`{{`}} $labels.integration {{`}}`}} sent from any instance in the {{`{{`}}$labels.job{{`}}`}} cluster is {{`{{`}} $value | humanizePercentage {{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerclusterfailedtosendalerts
+ summary: All Alertmanager instances in a cluster failed to send notifications to a non-critical integration.
+ expr: |-
+ min by (namespace,service, integration) (
+ rate(alertmanager_notifications_failed_total{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}", integration!~`.*`}[5m])
+ /
+ rate(alertmanager_notifications_total{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}", integration!~`.*`}[5m])
+ )
+ > 0.01
+ for: 5m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.AlertmanagerConfigInconsistent | default false) }}
+ - alert: AlertmanagerConfigInconsistent
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Alertmanager instances within the {{`{{`}}$labels.job{{`}}`}} cluster have different configurations.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerconfiginconsistent
+ summary: Alertmanager instances within the same cluster have different configurations.
+ expr: |-
+ count by (namespace,service) (
+ count_values by (namespace,service) ("config_hash", alertmanager_config_hash{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"})
+ )
+ != 1
+ for: 20m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.AlertmanagerClusterDown | default false) }}
+ - alert: AlertmanagerClusterDown
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} $value | humanizePercentage {{`}}`}} of Alertmanager instances within the {{`{{`}}$labels.job{{`}}`}} cluster have been up for less than half of the last 5m.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerclusterdown
+ summary: Half or more of the Alertmanager instances within the same cluster are down.
+ expr: |-
+ (
+ count by (namespace,service) (
+ avg_over_time(up{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[5m]) < 0.5
+ )
+ /
+ count by (namespace,service) (
+ up{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}
+ )
+ )
+ >= 0.5
+ for: 5m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.AlertmanagerClusterCrashlooping | default false) }}
+ - alert: AlertmanagerClusterCrashlooping
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} $value | humanizePercentage {{`}}`}} of Alertmanager instances within the {{`{{`}}$labels.job{{`}}`}} cluster have restarted at least 5 times in the last 10m.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerclustercrashlooping
+ summary: Half or more of the Alertmanager instances within the same cluster are crashlooping.
+ expr: |-
+ (
+ count by (namespace,service) (
+ changes(process_start_time_seconds{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[10m]) > 4
+ )
+ /
+ count by (namespace,service) (
+ up{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}
+ )
+ )
+ >= 0.5
+ for: 5m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/config-reloaders.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/config-reloaders.yaml
new file mode 100644
index 00000000..37109eb0
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/config-reloaders.yaml
@@ -0,0 +1,46 @@
+{{- /*
+Generated from 'config-reloaders' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/prometheusOperator-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.configReloaders }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "config-reloaders" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: config-reloaders
+ rules:
+{{- if not (.Values.defaultRules.disabled.ConfigReloaderSidecarErrors | default false) }}
+ - alert: ConfigReloaderSidecarErrors
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'Errors encountered while the {{`{{`}}$labels.pod{{`}}`}} config-reloader sidecar attempts to sync config in {{`{{`}}$labels.namespace{{`}}`}} namespace.
+
+ As a result, configuration for service running in {{`{{`}}$labels.pod{{`}}`}} may be stale and cannot be updated anymore.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/configreloadersidecarerrors
+ summary: config-reloader sidecar has not had a successful reload for 10m
+ expr: max_over_time(reloader_last_reload_successful{namespace=~".+"}[5m]) == 0
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/etcd.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/etcd.yaml
new file mode 100644
index 00000000..a0af3582
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/etcd.yaml
@@ -0,0 +1,294 @@
+{{- /*
+Generated from 'etcd' group from https://raw.githubusercontent.com/etcd-io/etcd/main/contrib/mixin/mixin.libsonnet
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeEtcd.enabled .Values.defaultRules.rules.etcd }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "etcd" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: etcd
+ rules:
+{{- if not (.Values.defaultRules.disabled.etcdMembersDown | default false) }}
+ - alert: etcdMembersDown
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": members are down ({{`{{`}} $value {{`}}`}}).'
+ summary: etcd cluster members are down.
+ expr: |-
+ max without (endpoint) (
+ sum without (instance) (up{job=~".*etcd.*"} == bool 0)
+ or
+ count without (To) (
+ sum without (instance) (rate(etcd_network_peer_sent_failures_total{job=~".*etcd.*"}[120s])) > 0.01
+ )
+ )
+ > 0
+ for: 10m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdInsufficientMembers | default false) }}
+ - alert: etcdInsufficientMembers
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": insufficient members ({{`{{`}} $value {{`}}`}}).'
+ summary: etcd cluster has insufficient number of members.
+ expr: sum(up{job=~".*etcd.*"} == bool 1) without (instance) < ((count(up{job=~".*etcd.*"}) without (instance) + 1) / 2)
+ for: 3m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdNoLeader | default false) }}
+ - alert: etcdNoLeader
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": member {{`{{`}} $labels.instance {{`}}`}} has no leader.'
+ summary: etcd cluster has no leader.
+ expr: etcd_server_has_leader{job=~".*etcd.*"} == 0
+ for: 1m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdHighNumberOfLeaderChanges | default false) }}
+ - alert: etcdHighNumberOfLeaderChanges
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": {{`{{`}} $value {{`}}`}} leader changes within the last 15 minutes. Frequent elections may be a sign of insufficient resources, high network latency, or disruptions by other components and should be investigated.'
+ summary: etcd cluster has high number of leader changes.
+ expr: increase((max without (instance) (etcd_server_leader_changes_seen_total{job=~".*etcd.*"}) or 0*absent(etcd_server_leader_changes_seen_total{job=~".*etcd.*"}))[15m:1m]) >= 4
+ for: 5m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdHighNumberOfFailedGRPCRequests | default false) }}
+ - alert: etcdHighNumberOfFailedGRPCRequests
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": {{`{{`}} $value {{`}}`}}% of requests for {{`{{`}} $labels.grpc_method {{`}}`}} failed on etcd instance {{`{{`}} $labels.instance {{`}}`}}.'
+ summary: etcd cluster has high number of failed grpc requests.
+ expr: |-
+ 100 * sum(rate(grpc_server_handled_total{job=~".*etcd.*", grpc_code=~"Unknown|FailedPrecondition|ResourceExhausted|Internal|Unavailable|DataLoss|DeadlineExceeded"}[5m])) without (grpc_type, grpc_code)
+ /
+ sum(rate(grpc_server_handled_total{job=~".*etcd.*"}[5m])) without (grpc_type, grpc_code)
+ > 1
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdHighNumberOfFailedGRPCRequests | default false) }}
+ - alert: etcdHighNumberOfFailedGRPCRequests
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": {{`{{`}} $value {{`}}`}}% of requests for {{`{{`}} $labels.grpc_method {{`}}`}} failed on etcd instance {{`{{`}} $labels.instance {{`}}`}}.'
+ summary: etcd cluster has high number of failed grpc requests.
+ expr: |-
+ 100 * sum(rate(grpc_server_handled_total{job=~".*etcd.*", grpc_code=~"Unknown|FailedPrecondition|ResourceExhausted|Internal|Unavailable|DataLoss|DeadlineExceeded"}[5m])) without (grpc_type, grpc_code)
+ /
+ sum(rate(grpc_server_handled_total{job=~".*etcd.*"}[5m])) without (grpc_type, grpc_code)
+ > 5
+ for: 5m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdGRPCRequestsSlow | default false) }}
+ - alert: etcdGRPCRequestsSlow
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": 99th percentile of gRPC requests is {{`{{`}} $value {{`}}`}}s on etcd instance {{`{{`}} $labels.instance {{`}}`}} for {{`{{`}} $labels.grpc_method {{`}}`}} method.'
+ summary: etcd grpc requests are slow
+ expr: |-
+ histogram_quantile(0.99, sum(rate(grpc_server_handling_seconds_bucket{job=~".*etcd.*", grpc_method!="Defragment", grpc_type="unary"}[5m])) without(grpc_type))
+ > 0.15
+ for: 10m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdMemberCommunicationSlow | default false) }}
+ - alert: etcdMemberCommunicationSlow
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": member communication with {{`{{`}} $labels.To {{`}}`}} is taking {{`{{`}} $value {{`}}`}}s on etcd instance {{`{{`}} $labels.instance {{`}}`}}.'
+ summary: etcd cluster member communication is slow.
+ expr: |-
+ histogram_quantile(0.99, rate(etcd_network_peer_round_trip_time_seconds_bucket{job=~".*etcd.*"}[5m]))
+ > 0.15
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdHighNumberOfFailedProposals | default false) }}
+ - alert: etcdHighNumberOfFailedProposals
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": {{`{{`}} $value {{`}}`}} proposal failures within the last 30 minutes on etcd instance {{`{{`}} $labels.instance {{`}}`}}.'
+ summary: etcd cluster has high number of proposal failures.
+ expr: rate(etcd_server_proposals_failed_total{job=~".*etcd.*"}[15m]) > 5
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdHighFsyncDurations | default false) }}
+ - alert: etcdHighFsyncDurations
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": 99th percentile fsync durations are {{`{{`}} $value {{`}}`}}s on etcd instance {{`{{`}} $labels.instance {{`}}`}}.'
+ summary: etcd cluster 99th percentile fsync durations are too high.
+ expr: |-
+ histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket{job=~".*etcd.*"}[5m]))
+ > 0.5
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdHighFsyncDurations | default false) }}
+ - alert: etcdHighFsyncDurations
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": 99th percentile fsync durations are {{`{{`}} $value {{`}}`}}s on etcd instance {{`{{`}} $labels.instance {{`}}`}}.'
+ summary: etcd cluster 99th percentile fsync durations are too high.
+ expr: |-
+ histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket{job=~".*etcd.*"}[5m]))
+ > 1
+ for: 10m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdHighCommitDurations | default false) }}
+ - alert: etcdHighCommitDurations
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": 99th percentile commit durations {{`{{`}} $value {{`}}`}}s on etcd instance {{`{{`}} $labels.instance {{`}}`}}.'
+ summary: etcd cluster 99th percentile commit durations are too high.
+ expr: |-
+ histogram_quantile(0.99, rate(etcd_disk_backend_commit_duration_seconds_bucket{job=~".*etcd.*"}[5m]))
+ > 0.25
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdDatabaseQuotaLowSpace | default false) }}
+ - alert: etcdDatabaseQuotaLowSpace
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": database size exceeds the defined quota on etcd instance {{`{{`}} $labels.instance {{`}}`}}, please defrag or increase the quota as the writes to etcd will be disabled when it is full.'
+ summary: etcd cluster database is running full.
+ expr: (last_over_time(etcd_mvcc_db_total_size_in_bytes[5m]) / last_over_time(etcd_server_quota_backend_bytes[5m]))*100 > 95
+ for: 10m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdExcessiveDatabaseGrowth | default false) }}
+ - alert: etcdExcessiveDatabaseGrowth
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": Predicting running out of disk space in the next four hours, based on write observations within the past four hours on etcd instance {{`{{`}} $labels.instance {{`}}`}}, please check as it might be disruptive.'
+ summary: etcd cluster database growing very fast.
+ expr: predict_linear(etcd_mvcc_db_total_size_in_bytes[4h], 4*60*60) > etcd_server_quota_backend_bytes
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.etcdDatabaseHighFragmentationRatio | default false) }}
+ - alert: etcdDatabaseHighFragmentationRatio
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": database size in use on instance {{`{{`}} $labels.instance {{`}}`}} is {{`{{`}} $value | humanizePercentage {{`}}`}} of the actual allocated disk space, please run defragmentation (e.g. etcdctl defrag) to retrieve the unused fragmented disk space.'
+ runbook_url: https://etcd.io/docs/v3.5/op-guide/maintenance/#defragmentation
+ summary: etcd database size in use is less than 50% of the actual allocated storage.
+ expr: (last_over_time(etcd_mvcc_db_total_size_in_use_in_bytes[5m]) / last_over_time(etcd_mvcc_db_total_size_in_bytes[5m])) < 0.5
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/general.rules.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/general.rules.yaml
new file mode 100644
index 00000000..7ab648bc
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/general.rules.yaml
@@ -0,0 +1,98 @@
+{{- /*
+Generated from 'general.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubePrometheus-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.general }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "general.rules" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: general.rules
+ rules:
+{{- if not (.Values.defaultRules.disabled.TargetDown | default false) }}
+ - alert: TargetDown
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} printf "%.4g" $value {{`}}`}}% of the {{`{{`}} $labels.job {{`}}`}}/{{`{{`}} $labels.service {{`}}`}} targets in {{`{{`}} $labels.namespace {{`}}`}} namespace are down.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/general/targetdown
+ summary: One or more targets are unreachable.
+ expr: 100 * (count(up == 0) BY (job, namespace, service) / count(up) BY (job, namespace, service)) > 10
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.Watchdog | default false) }}
+ - alert: Watchdog
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'This is an alert meant to ensure that the entire alerting pipeline is functional.
+
+ This alert is always firing, therefore it should always be firing in Alertmanager
+
+ and always fire against a receiver. There are integrations with various notification
+
+ mechanisms that send a notification when this alert is not firing. For example the
+
+ "DeadMansSnitch" integration in PagerDuty.
+
+ '
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/general/watchdog
+ summary: An alert that should always be firing to certify that Alertmanager is working properly.
+ expr: vector(1)
+ labels:
+ severity: none
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.InfoInhibitor | default false) }}
+ - alert: InfoInhibitor
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'This is an alert that is used to inhibit info alerts.
+
+ By themselves, the info-level alerts are sometimes very noisy, but they are relevant when combined with
+
+ other alerts.
+
+ This alert fires whenever there''s a severity="info" alert, and stops firing when another alert with a
+
+ severity of ''warning'' or ''critical'' starts firing on the same namespace.
+
+ This alert should be routed to a null receiver and configured to inhibit alerts with severity="info".
+
+ '
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/general/infoinhibitor
+ summary: Info-level alert inhibition.
+ expr: ALERTS{severity = "info"} == 1 unless on(namespace) ALERTS{alertname != "InfoInhibitor", severity =~ "warning|critical", alertstate="firing"} == 1
+ labels:
+ severity: none
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/k8s.rules.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/k8s.rules.yaml
new file mode 100644
index 00000000..b88b9b28
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/k8s.rules.yaml
@@ -0,0 +1,173 @@
+{{- /*
+Generated from 'k8s.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.k8s }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "k8s.rules" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: k8s.rules
+ rules:
+ - expr: |-
+ sum by (cluster, namespace, pod, container) (
+ irate(container_cpu_usage_seconds_total{job="kubelet", metrics_path="/metrics/cadvisor", image!=""}[5m])
+ ) * on (cluster, namespace, pod) group_left(node) topk by (cluster, namespace, pod) (
+ 1, max by(cluster, namespace, pod, node) (kube_pod_info{node!=""})
+ )
+ record: node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate
+ - expr: |-
+ container_memory_working_set_bytes{job="kubelet", metrics_path="/metrics/cadvisor", image!=""}
+ * on (namespace, pod) group_left(node) topk by(namespace, pod) (1,
+ max by(namespace, pod, node) (kube_pod_info{node!=""})
+ )
+ record: node_namespace_pod_container:container_memory_working_set_bytes
+ - expr: |-
+ container_memory_rss{job="kubelet", metrics_path="/metrics/cadvisor", image!=""}
+ * on (namespace, pod) group_left(node) topk by(namespace, pod) (1,
+ max by(namespace, pod, node) (kube_pod_info{node!=""})
+ )
+ record: node_namespace_pod_container:container_memory_rss
+ - expr: |-
+ container_memory_cache{job="kubelet", metrics_path="/metrics/cadvisor", image!=""}
+ * on (namespace, pod) group_left(node) topk by(namespace, pod) (1,
+ max by(namespace, pod, node) (kube_pod_info{node!=""})
+ )
+ record: node_namespace_pod_container:container_memory_cache
+ - expr: |-
+ container_memory_swap{job="kubelet", metrics_path="/metrics/cadvisor", image!=""}
+ * on (namespace, pod) group_left(node) topk by(namespace, pod) (1,
+ max by(namespace, pod, node) (kube_pod_info{node!=""})
+ )
+ record: node_namespace_pod_container:container_memory_swap
+ - expr: |-
+ kube_pod_container_resource_requests{resource="memory",job="kube-state-metrics"} * on (namespace, pod, cluster)
+ group_left() max by (namespace, pod, cluster) (
+ (kube_pod_status_phase{phase=~"Pending|Running"} == 1)
+ )
+ record: cluster:namespace:pod_memory:active:kube_pod_container_resource_requests
+ - expr: |-
+ sum by (namespace, cluster) (
+ sum by (namespace, pod, cluster) (
+ max by (namespace, pod, container, cluster) (
+ kube_pod_container_resource_requests{resource="memory",job="kube-state-metrics"}
+ ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) (
+ kube_pod_status_phase{phase=~"Pending|Running"} == 1
+ )
+ )
+ )
+ record: namespace_memory:kube_pod_container_resource_requests:sum
+ - expr: |-
+ kube_pod_container_resource_requests{resource="cpu",job="kube-state-metrics"} * on (namespace, pod, cluster)
+ group_left() max by (namespace, pod, cluster) (
+ (kube_pod_status_phase{phase=~"Pending|Running"} == 1)
+ )
+ record: cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests
+ - expr: |-
+ sum by (namespace, cluster) (
+ sum by (namespace, pod, cluster) (
+ max by (namespace, pod, container, cluster) (
+ kube_pod_container_resource_requests{resource="cpu",job="kube-state-metrics"}
+ ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) (
+ kube_pod_status_phase{phase=~"Pending|Running"} == 1
+ )
+ )
+ )
+ record: namespace_cpu:kube_pod_container_resource_requests:sum
+ - expr: |-
+ kube_pod_container_resource_limits{resource="memory",job="kube-state-metrics"} * on (namespace, pod, cluster)
+ group_left() max by (namespace, pod, cluster) (
+ (kube_pod_status_phase{phase=~"Pending|Running"} == 1)
+ )
+ record: cluster:namespace:pod_memory:active:kube_pod_container_resource_limits
+ - expr: |-
+ sum by (namespace, cluster) (
+ sum by (namespace, pod, cluster) (
+ max by (namespace, pod, container, cluster) (
+ kube_pod_container_resource_limits{resource="memory",job="kube-state-metrics"}
+ ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) (
+ kube_pod_status_phase{phase=~"Pending|Running"} == 1
+ )
+ )
+ )
+ record: namespace_memory:kube_pod_container_resource_limits:sum
+ - expr: |-
+ kube_pod_container_resource_limits{resource="cpu",job="kube-state-metrics"} * on (namespace, pod, cluster)
+ group_left() max by (namespace, pod, cluster) (
+ (kube_pod_status_phase{phase=~"Pending|Running"} == 1)
+ )
+ record: cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits
+ - expr: |-
+ sum by (namespace, cluster) (
+ sum by (namespace, pod, cluster) (
+ max by (namespace, pod, container, cluster) (
+ kube_pod_container_resource_limits{resource="cpu",job="kube-state-metrics"}
+ ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) (
+ kube_pod_status_phase{phase=~"Pending|Running"} == 1
+ )
+ )
+ )
+ record: namespace_cpu:kube_pod_container_resource_limits:sum
+ - expr: |-
+ max by (cluster, namespace, workload, pod) (
+ label_replace(
+ label_replace(
+ kube_pod_owner{job="kube-state-metrics", owner_kind="ReplicaSet"},
+ "replicaset", "$1", "owner_name", "(.*)"
+ ) * on(replicaset, namespace) group_left(owner_name) topk by(replicaset, namespace) (
+ 1, max by (replicaset, namespace, owner_name) (
+ kube_replicaset_owner{job="kube-state-metrics"}
+ )
+ ),
+ "workload", "$1", "owner_name", "(.*)"
+ )
+ )
+ labels:
+ workload_type: deployment
+ record: namespace_workload_pod:kube_pod_owner:relabel
+ - expr: |-
+ max by (cluster, namespace, workload, pod) (
+ label_replace(
+ kube_pod_owner{job="kube-state-metrics", owner_kind="DaemonSet"},
+ "workload", "$1", "owner_name", "(.*)"
+ )
+ )
+ labels:
+ workload_type: daemonset
+ record: namespace_workload_pod:kube_pod_owner:relabel
+ - expr: |-
+ max by (cluster, namespace, workload, pod) (
+ label_replace(
+ kube_pod_owner{job="kube-state-metrics", owner_kind="StatefulSet"},
+ "workload", "$1", "owner_name", "(.*)"
+ )
+ )
+ labels:
+ workload_type: statefulset
+ record: namespace_workload_pod:kube_pod_owner:relabel
+ - expr: |-
+ max by (cluster, namespace, workload, pod) (
+ label_replace(
+ kube_pod_owner{job="kube-state-metrics", owner_kind="Job"},
+ "workload", "$1", "owner_name", "(.*)"
+ )
+ )
+ labels:
+ workload_type: job
+ record: namespace_workload_pod:kube_pod_owner:relabel
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-availability.rules.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-availability.rules.yaml
new file mode 100644
index 00000000..bae96b90
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-availability.rules.yaml
@@ -0,0 +1,136 @@
+{{- /*
+Generated from 'kube-apiserver-availability.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeApiServer.enabled .Values.defaultRules.rules.kubeApiserverAvailability }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-apiserver-availability.rules" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - interval: 3m
+ name: kube-apiserver-availability.rules
+ rules:
+ - expr: avg_over_time(code_verb:apiserver_request_total:increase1h[30d]) * 24 * 30
+ record: code_verb:apiserver_request_total:increase30d
+ - expr: sum by (cluster, code) (code_verb:apiserver_request_total:increase30d{verb=~"LIST|GET"})
+ labels:
+ verb: read
+ record: code:apiserver_request_total:increase30d
+ - expr: sum by (cluster, code) (code_verb:apiserver_request_total:increase30d{verb=~"POST|PUT|PATCH|DELETE"})
+ labels:
+ verb: write
+ record: code:apiserver_request_total:increase30d
+ - expr: sum by (cluster, verb, scope) (increase(apiserver_request_slo_duration_seconds_count[1h]))
+ record: cluster_verb_scope:apiserver_request_slo_duration_seconds_count:increase1h
+ - expr: sum by (cluster, verb, scope) (avg_over_time(cluster_verb_scope:apiserver_request_slo_duration_seconds_count:increase1h[30d]) * 24 * 30)
+ record: cluster_verb_scope:apiserver_request_slo_duration_seconds_count:increase30d
+ - expr: sum by (cluster, verb, scope, le) (increase(apiserver_request_slo_duration_seconds_bucket[1h]))
+ record: cluster_verb_scope_le:apiserver_request_slo_duration_seconds_bucket:increase1h
+ - expr: sum by (cluster, verb, scope, le) (avg_over_time(cluster_verb_scope_le:apiserver_request_slo_duration_seconds_bucket:increase1h[30d]) * 24 * 30)
+ record: cluster_verb_scope_le:apiserver_request_slo_duration_seconds_bucket:increase30d
+ - expr: |-
+ 1 - (
+ (
+ # write too slow
+ sum by (cluster) (cluster_verb_scope:apiserver_request_slo_duration_seconds_count:increase30d{verb=~"POST|PUT|PATCH|DELETE"})
+ -
+ sum by (cluster) (cluster_verb_scope_le:apiserver_request_slo_duration_seconds_bucket:increase30d{verb=~"POST|PUT|PATCH|DELETE",le="1"})
+ ) +
+ (
+ # read too slow
+ sum by (cluster) (cluster_verb_scope:apiserver_request_slo_duration_seconds_count:increase30d{verb=~"LIST|GET"})
+ -
+ (
+ (
+ sum by (cluster) (cluster_verb_scope_le:apiserver_request_slo_duration_seconds_bucket:increase30d{verb=~"LIST|GET",scope=~"resource|",le="1"})
+ or
+ vector(0)
+ )
+ +
+ sum by (cluster) (cluster_verb_scope_le:apiserver_request_slo_duration_seconds_bucket:increase30d{verb=~"LIST|GET",scope="namespace",le="5"})
+ +
+ sum by (cluster) (cluster_verb_scope_le:apiserver_request_slo_duration_seconds_bucket:increase30d{verb=~"LIST|GET",scope="cluster",le="30"})
+ )
+ ) +
+ # errors
+ sum by (cluster) (code:apiserver_request_total:increase30d{code=~"5.."} or vector(0))
+ )
+ /
+ sum by (cluster) (code:apiserver_request_total:increase30d)
+ labels:
+ verb: all
+ record: apiserver_request:availability30d
+ - expr: |-
+ 1 - (
+ sum by (cluster) (cluster_verb_scope:apiserver_request_slo_duration_seconds_count:increase30d{verb=~"LIST|GET"})
+ -
+ (
+ # too slow
+ (
+ sum by (cluster) (cluster_verb_scope_le:apiserver_request_slo_duration_seconds_bucket:increase30d{verb=~"LIST|GET",scope=~"resource|",le="1"})
+ or
+ vector(0)
+ )
+ +
+ sum by (cluster) (cluster_verb_scope_le:apiserver_request_slo_duration_seconds_bucket:increase30d{verb=~"LIST|GET",scope="namespace",le="5"})
+ +
+ sum by (cluster) (cluster_verb_scope_le:apiserver_request_slo_duration_seconds_bucket:increase30d{verb=~"LIST|GET",scope="cluster",le="30"})
+ )
+ +
+ # errors
+ sum by (cluster) (code:apiserver_request_total:increase30d{verb="read",code=~"5.."} or vector(0))
+ )
+ /
+ sum by (cluster) (code:apiserver_request_total:increase30d{verb="read"})
+ labels:
+ verb: read
+ record: apiserver_request:availability30d
+ - expr: |-
+ 1 - (
+ (
+ # too slow
+ sum by (cluster) (cluster_verb_scope:apiserver_request_slo_duration_seconds_count:increase30d{verb=~"POST|PUT|PATCH|DELETE"})
+ -
+ sum by (cluster) (cluster_verb_scope_le:apiserver_request_slo_duration_seconds_bucket:increase30d{verb=~"POST|PUT|PATCH|DELETE",le="1"})
+ )
+ +
+ # errors
+ sum by (cluster) (code:apiserver_request_total:increase30d{verb="write",code=~"5.."} or vector(0))
+ )
+ /
+ sum by (cluster) (code:apiserver_request_total:increase30d{verb="write"})
+ labels:
+ verb: write
+ record: apiserver_request:availability30d
+ - expr: sum by (cluster,code,resource) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[5m]))
+ labels:
+ verb: read
+ record: code_resource:apiserver_request_total:rate5m
+ - expr: sum by (cluster,code,resource) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[5m]))
+ labels:
+ verb: write
+ record: code_resource:apiserver_request_total:rate5m
+ - expr: sum by (cluster, code, verb) (increase(apiserver_request_total{job="apiserver",verb=~"LIST|GET|POST|PUT|PATCH|DELETE",code=~"2.."}[1h]))
+ record: code_verb:apiserver_request_total:increase1h
+ - expr: sum by (cluster, code, verb) (increase(apiserver_request_total{job="apiserver",verb=~"LIST|GET|POST|PUT|PATCH|DELETE",code=~"3.."}[1h]))
+ record: code_verb:apiserver_request_total:increase1h
+ - expr: sum by (cluster, code, verb) (increase(apiserver_request_total{job="apiserver",verb=~"LIST|GET|POST|PUT|PATCH|DELETE",code=~"4.."}[1h]))
+ record: code_verb:apiserver_request_total:increase1h
+ - expr: sum by (cluster, code, verb) (increase(apiserver_request_total{job="apiserver",verb=~"LIST|GET|POST|PUT|PATCH|DELETE",code=~"5.."}[1h]))
+ record: code_verb:apiserver_request_total:increase1h
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-burnrate.rules.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-burnrate.rules.yaml
new file mode 100644
index 00000000..6774fc35
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-burnrate.rules.yaml
@@ -0,0 +1,328 @@
+{{- /*
+Generated from 'kube-apiserver-burnrate.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeApiServer.enabled .Values.defaultRules.rules.kubeApiserverBurnrate }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-apiserver-burnrate.rules" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kube-apiserver-burnrate.rules
+ rules:
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[1d]))
+ -
+ (
+ (
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[1d]))
+ or
+ vector(0)
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[1d]))
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[1d]))
+ )
+ )
+ +
+ # errors
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[1d]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[1d]))
+ labels:
+ verb: read
+ record: apiserver_request:burnrate1d
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[1h]))
+ -
+ (
+ (
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[1h]))
+ or
+ vector(0)
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[1h]))
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[1h]))
+ )
+ )
+ +
+ # errors
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[1h]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[1h]))
+ labels:
+ verb: read
+ record: apiserver_request:burnrate1h
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[2h]))
+ -
+ (
+ (
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[2h]))
+ or
+ vector(0)
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[2h]))
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[2h]))
+ )
+ )
+ +
+ # errors
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[2h]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[2h]))
+ labels:
+ verb: read
+ record: apiserver_request:burnrate2h
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[30m]))
+ -
+ (
+ (
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[30m]))
+ or
+ vector(0)
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[30m]))
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[30m]))
+ )
+ )
+ +
+ # errors
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[30m]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[30m]))
+ labels:
+ verb: read
+ record: apiserver_request:burnrate30m
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[3d]))
+ -
+ (
+ (
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[3d]))
+ or
+ vector(0)
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[3d]))
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[3d]))
+ )
+ )
+ +
+ # errors
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[3d]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[3d]))
+ labels:
+ verb: read
+ record: apiserver_request:burnrate3d
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[5m]))
+ -
+ (
+ (
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[5m]))
+ or
+ vector(0)
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[5m]))
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[5m]))
+ )
+ )
+ +
+ # errors
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[5m]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[5m]))
+ labels:
+ verb: read
+ record: apiserver_request:burnrate5m
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[6h]))
+ -
+ (
+ (
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[6h]))
+ or
+ vector(0)
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[6h]))
+ +
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[6h]))
+ )
+ )
+ +
+ # errors
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[6h]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[6h]))
+ labels:
+ verb: read
+ record: apiserver_request:burnrate6h
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[1d]))
+ -
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[1d]))
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[1d]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[1d]))
+ labels:
+ verb: write
+ record: apiserver_request:burnrate1d
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[1h]))
+ -
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[1h]))
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[1h]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[1h]))
+ labels:
+ verb: write
+ record: apiserver_request:burnrate1h
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[2h]))
+ -
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[2h]))
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[2h]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[2h]))
+ labels:
+ verb: write
+ record: apiserver_request:burnrate2h
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[30m]))
+ -
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[30m]))
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[30m]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[30m]))
+ labels:
+ verb: write
+ record: apiserver_request:burnrate30m
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[3d]))
+ -
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[3d]))
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[3d]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[3d]))
+ labels:
+ verb: write
+ record: apiserver_request:burnrate3d
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[5m]))
+ -
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[5m]))
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[5m]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[5m]))
+ labels:
+ verb: write
+ record: apiserver_request:burnrate5m
+ - expr: |-
+ (
+ (
+ # too slow
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[6h]))
+ -
+ sum by (cluster) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[6h]))
+ )
+ +
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[6h]))
+ )
+ /
+ sum by (cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[6h]))
+ labels:
+ verb: write
+ record: apiserver_request:burnrate6h
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-histogram.rules.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-histogram.rules.yaml
new file mode 100644
index 00000000..762bcc6d
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-histogram.rules.yaml
@@ -0,0 +1,37 @@
+{{- /*
+Generated from 'kube-apiserver-histogram.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeApiServer.enabled .Values.defaultRules.rules.kubeApiserverHistogram }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-apiserver-histogram.rules" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kube-apiserver-histogram.rules
+ rules:
+ - expr: histogram_quantile(0.99, sum by (cluster, le, resource) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[5m]))) > 0
+ labels:
+ quantile: '0.99'
+ verb: read
+ record: cluster_quantile:apiserver_request_slo_duration_seconds:histogram_quantile
+ - expr: histogram_quantile(0.99, sum by (cluster, le, resource) (rate(apiserver_request_slo_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[5m]))) > 0
+ labels:
+ quantile: '0.99'
+ verb: write
+ record: cluster_quantile:apiserver_request_slo_duration_seconds:histogram_quantile
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-slos.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-slos.yaml
new file mode 100644
index 00000000..867fe20d
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-slos.yaml
@@ -0,0 +1,115 @@
+{{- /*
+Generated from 'kube-apiserver-slos' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeApiServer.enabled .Values.defaultRules.rules.kubeApiserverSlos }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-apiserver-slos" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kube-apiserver-slos
+ rules:
+{{- if not (.Values.defaultRules.disabled.KubeAPIErrorBudgetBurn | default false) }}
+ - alert: KubeAPIErrorBudgetBurn
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: The API server is burning too much error budget.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeapierrorbudgetburn
+ summary: The API server is burning too much error budget.
+ expr: |-
+ sum(apiserver_request:burnrate1h) > (14.40 * 0.01000)
+ and
+ sum(apiserver_request:burnrate5m) > (14.40 * 0.01000)
+ for: 2m
+ labels:
+ long: 1h
+ severity: critical
+ short: 5m
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeAPIErrorBudgetBurn | default false) }}
+ - alert: KubeAPIErrorBudgetBurn
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: The API server is burning too much error budget.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeapierrorbudgetburn
+ summary: The API server is burning too much error budget.
+ expr: |-
+ sum(apiserver_request:burnrate6h) > (6.00 * 0.01000)
+ and
+ sum(apiserver_request:burnrate30m) > (6.00 * 0.01000)
+ for: 15m
+ labels:
+ long: 6h
+ severity: critical
+ short: 30m
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeAPIErrorBudgetBurn | default false) }}
+ - alert: KubeAPIErrorBudgetBurn
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: The API server is burning too much error budget.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeapierrorbudgetburn
+ summary: The API server is burning too much error budget.
+ expr: |-
+ sum(apiserver_request:burnrate1d) > (3.00 * 0.01000)
+ and
+ sum(apiserver_request:burnrate2h) > (3.00 * 0.01000)
+ for: 1h
+ labels:
+ long: 1d
+ severity: warning
+ short: 2h
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeAPIErrorBudgetBurn | default false) }}
+ - alert: KubeAPIErrorBudgetBurn
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: The API server is burning too much error budget.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeapierrorbudgetburn
+ summary: The API server is burning too much error budget.
+ expr: |-
+ sum(apiserver_request:burnrate3d) > (1.00 * 0.01000)
+ and
+ sum(apiserver_request:burnrate6h) > (1.00 * 0.01000)
+ for: 3h
+ labels:
+ long: 3d
+ severity: warning
+ short: 6h
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-prometheus-general.rules.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-prometheus-general.rules.yaml
new file mode 100644
index 00000000..78a3db1c
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-prometheus-general.rules.yaml
@@ -0,0 +1,31 @@
+{{- /*
+Generated from 'kube-prometheus-general.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubePrometheus-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubePrometheusGeneral }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-prometheus-general.rules" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kube-prometheus-general.rules
+ rules:
+ - expr: count without(instance, pod, node) (up == 1)
+ record: count:up1
+ - expr: count without(instance, pod, node) (up == 0)
+ record: count:up0
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-prometheus-node-recording.rules.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-prometheus-node-recording.rules.yaml
new file mode 100644
index 00000000..0cd0ba5b
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-prometheus-node-recording.rules.yaml
@@ -0,0 +1,39 @@
+{{- /*
+Generated from 'kube-prometheus-node-recording.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubePrometheus-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubePrometheusNodeRecording }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-prometheus-node-recording.rules" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kube-prometheus-node-recording.rules
+ rules:
+ - expr: sum(rate(node_cpu_seconds_total{mode!="idle",mode!="iowait",mode!="steal"}[3m])) BY (instance)
+ record: instance:node_cpu:rate:sum
+ - expr: sum(rate(node_network_receive_bytes_total[3m])) BY (instance)
+ record: instance:node_network_receive_bytes:rate:sum
+ - expr: sum(rate(node_network_transmit_bytes_total[3m])) BY (instance)
+ record: instance:node_network_transmit_bytes:rate:sum
+ - expr: sum(rate(node_cpu_seconds_total{mode!="idle",mode!="iowait",mode!="steal"}[5m])) WITHOUT (cpu, mode) / ON(instance) GROUP_LEFT() count(sum(node_cpu_seconds_total) BY (instance, cpu)) BY (instance)
+ record: instance:node_cpu:ratio
+ - expr: sum(rate(node_cpu_seconds_total{mode!="idle",mode!="iowait",mode!="steal"}[5m]))
+ record: cluster:node_cpu:sum_rate5m
+ - expr: cluster:node_cpu:sum_rate5m / count(sum(node_cpu_seconds_total) BY (instance, cpu))
+ record: cluster:node_cpu:ratio
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-scheduler.rules.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-scheduler.rules.yaml
new file mode 100644
index 00000000..dde6a2f2
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-scheduler.rules.yaml
@@ -0,0 +1,63 @@
+{{- /*
+Generated from 'kube-scheduler.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeScheduler.enabled .Values.defaultRules.rules.kubeScheduler }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-scheduler.rules" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kube-scheduler.rules
+ rules:
+ - expr: histogram_quantile(0.99, sum(rate(scheduler_e2e_scheduling_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod))
+ labels:
+ quantile: '0.99'
+ record: cluster_quantile:scheduler_e2e_scheduling_duration_seconds:histogram_quantile
+ - expr: histogram_quantile(0.99, sum(rate(scheduler_scheduling_algorithm_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod))
+ labels:
+ quantile: '0.99'
+ record: cluster_quantile:scheduler_scheduling_algorithm_duration_seconds:histogram_quantile
+ - expr: histogram_quantile(0.99, sum(rate(scheduler_binding_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod))
+ labels:
+ quantile: '0.99'
+ record: cluster_quantile:scheduler_binding_duration_seconds:histogram_quantile
+ - expr: histogram_quantile(0.9, sum(rate(scheduler_e2e_scheduling_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod))
+ labels:
+ quantile: '0.9'
+ record: cluster_quantile:scheduler_e2e_scheduling_duration_seconds:histogram_quantile
+ - expr: histogram_quantile(0.9, sum(rate(scheduler_scheduling_algorithm_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod))
+ labels:
+ quantile: '0.9'
+ record: cluster_quantile:scheduler_scheduling_algorithm_duration_seconds:histogram_quantile
+ - expr: histogram_quantile(0.9, sum(rate(scheduler_binding_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod))
+ labels:
+ quantile: '0.9'
+ record: cluster_quantile:scheduler_binding_duration_seconds:histogram_quantile
+ - expr: histogram_quantile(0.5, sum(rate(scheduler_e2e_scheduling_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod))
+ labels:
+ quantile: '0.5'
+ record: cluster_quantile:scheduler_e2e_scheduling_duration_seconds:histogram_quantile
+ - expr: histogram_quantile(0.5, sum(rate(scheduler_scheduling_algorithm_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod))
+ labels:
+ quantile: '0.5'
+ record: cluster_quantile:scheduler_scheduling_algorithm_duration_seconds:histogram_quantile
+ - expr: histogram_quantile(0.5, sum(rate(scheduler_binding_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod))
+ labels:
+ quantile: '0.5'
+ record: cluster_quantile:scheduler_binding_duration_seconds:histogram_quantile
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-state-metrics.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-state-metrics.yaml
new file mode 100644
index 00000000..7547436a
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-state-metrics.yaml
@@ -0,0 +1,107 @@
+{{- /*
+Generated from 'kube-state-metrics' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubeStateMetrics-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubeStateMetrics }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-state-metrics" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kube-state-metrics
+ rules:
+{{- if not (.Values.defaultRules.disabled.KubeStateMetricsListErrors | default false) }}
+ - alert: KubeStateMetricsListErrors
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: kube-state-metrics is experiencing errors at an elevated rate in list operations. This is likely causing it to not be able to expose metrics about Kubernetes objects correctly or at all.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kube-state-metrics/kubestatemetricslisterrors
+ summary: kube-state-metrics is experiencing errors in list operations.
+ expr: |-
+ (sum(rate(kube_state_metrics_list_total{job="kube-state-metrics",result="error"}[5m]))
+ /
+ sum(rate(kube_state_metrics_list_total{job="kube-state-metrics"}[5m])))
+ > 0.01
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeStateMetricsWatchErrors | default false) }}
+ - alert: KubeStateMetricsWatchErrors
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: kube-state-metrics is experiencing errors at an elevated rate in watch operations. This is likely causing it to not be able to expose metrics about Kubernetes objects correctly or at all.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kube-state-metrics/kubestatemetricswatcherrors
+ summary: kube-state-metrics is experiencing errors in watch operations.
+ expr: |-
+ (sum(rate(kube_state_metrics_watch_total{job="kube-state-metrics",result="error"}[5m]))
+ /
+ sum(rate(kube_state_metrics_watch_total{job="kube-state-metrics"}[5m])))
+ > 0.01
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeStateMetricsShardingMismatch | default false) }}
+ - alert: KubeStateMetricsShardingMismatch
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: kube-state-metrics pods are running with different --total-shards configuration, some Kubernetes objects may be exposed multiple times or not exposed at all.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kube-state-metrics/kubestatemetricsshardingmismatch
+ summary: kube-state-metrics sharding is misconfigured.
+ expr: stdvar (kube_state_metrics_total_shards{job="kube-state-metrics"}) != 0
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeStateMetricsShardsMissing | default false) }}
+ - alert: KubeStateMetricsShardsMissing
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: kube-state-metrics shards are missing, some Kubernetes objects are not being exposed.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kube-state-metrics/kubestatemetricsshardsmissing
+ summary: kube-state-metrics shards are missing.
+ expr: |-
+ 2^max(kube_state_metrics_total_shards{job="kube-state-metrics"}) - 1
+ -
+ sum( 2 ^ max by (shard_ordinal) (kube_state_metrics_shard_ordinal{job="kube-state-metrics"}) )
+ != 0
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kubelet.rules.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubelet.rules.yaml
new file mode 100644
index 00000000..9176cd02
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubelet.rules.yaml
@@ -0,0 +1,39 @@
+{{- /*
+Generated from 'kubelet.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubelet.enabled .Values.defaultRules.rules.kubelet }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubelet.rules" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kubelet.rules
+ rules:
+ - expr: histogram_quantile(0.99, sum(rate(kubelet_pleg_relist_duration_seconds_bucket[5m])) by (cluster, instance, le) * on(cluster, instance) group_left(node) kubelet_node_name{job="kubelet", metrics_path="/metrics"})
+ labels:
+ quantile: '0.99'
+ record: node_quantile:kubelet_pleg_relist_duration_seconds:histogram_quantile
+ - expr: histogram_quantile(0.9, sum(rate(kubelet_pleg_relist_duration_seconds_bucket[5m])) by (cluster, instance, le) * on(cluster, instance) group_left(node) kubelet_node_name{job="kubelet", metrics_path="/metrics"})
+ labels:
+ quantile: '0.9'
+ record: node_quantile:kubelet_pleg_relist_duration_seconds:histogram_quantile
+ - expr: histogram_quantile(0.5, sum(rate(kubelet_pleg_relist_duration_seconds_bucket[5m])) by (cluster, instance, le) * on(cluster, instance) group_left(node) kubelet_node_name{job="kubelet", metrics_path="/metrics"})
+ labels:
+ quantile: '0.5'
+ record: node_quantile:kubelet_pleg_relist_duration_seconds:histogram_quantile
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-apps.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-apps.yaml
new file mode 100644
index 00000000..d13185e3
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-apps.yaml
@@ -0,0 +1,375 @@
+{{- /*
+Generated from 'kubernetes-apps' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubernetesApps }}
+{{- $targetNamespace := .Values.defaultRules.appNamespacesTarget }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-apps" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kubernetes-apps
+ rules:
+{{- if not (.Values.defaultRules.disabled.KubePodCrashLooping | default false) }}
+ - alert: KubePodCrashLooping
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: 'Pod {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.pod {{`}}`}} ({{`{{`}} $labels.container {{`}}`}}) is in waiting state (reason: "CrashLoopBackOff").'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepodcrashlooping
+ summary: Pod is crash looping.
+ expr: max_over_time(kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff", job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}[5m]) >= 1
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubePodNotReady | default false) }}
+ - alert: KubePodNotReady
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Pod {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.pod {{`}}`}} has been in a non-ready state for longer than 15 minutes.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepodnotready
+ summary: Pod has been in a non-ready state for more than 15 minutes.
+ expr: |-
+ sum by (namespace, pod, cluster) (
+ max by(namespace, pod, cluster) (
+ kube_pod_status_phase{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}", phase=~"Pending|Unknown"}
+ ) * on(namespace, pod, cluster) group_left(owner_kind) topk by(namespace, pod, cluster) (
+ 1, max by(namespace, pod, owner_kind, cluster) (kube_pod_owner{owner_kind!="Job"})
+ )
+ ) > 0
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeDeploymentGenerationMismatch | default false) }}
+ - alert: KubeDeploymentGenerationMismatch
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Deployment generation for {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.deployment {{`}}`}} does not match, this indicates that the Deployment has failed but has not been rolled back.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubedeploymentgenerationmismatch
+ summary: Deployment generation mismatch due to possible roll-back
+ expr: |-
+ kube_deployment_status_observed_generation{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ !=
+ kube_deployment_metadata_generation{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeDeploymentReplicasMismatch | default false) }}
+ - alert: KubeDeploymentReplicasMismatch
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Deployment {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.deployment {{`}}`}} has not matched the expected number of replicas for longer than 15 minutes.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubedeploymentreplicasmismatch
+ summary: Deployment has not matched the expected number of replicas.
+ expr: |-
+ (
+ kube_deployment_spec_replicas{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ >
+ kube_deployment_status_replicas_available{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ ) and (
+ changes(kube_deployment_status_replicas_updated{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}[10m])
+ ==
+ 0
+ )
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeStatefulSetReplicasMismatch | default false) }}
+ - alert: KubeStatefulSetReplicasMismatch
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: StatefulSet {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.statefulset {{`}}`}} has not matched the expected number of replicas for longer than 15 minutes.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubestatefulsetreplicasmismatch
+ summary: Deployment has not matched the expected number of replicas.
+ expr: |-
+ (
+ kube_statefulset_status_replicas_ready{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ !=
+ kube_statefulset_status_replicas{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ ) and (
+ changes(kube_statefulset_status_replicas_updated{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}[10m])
+ ==
+ 0
+ )
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeStatefulSetGenerationMismatch | default false) }}
+ - alert: KubeStatefulSetGenerationMismatch
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: StatefulSet generation for {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.statefulset {{`}}`}} does not match, this indicates that the StatefulSet has failed but has not been rolled back.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubestatefulsetgenerationmismatch
+ summary: StatefulSet generation mismatch due to possible roll-back
+ expr: |-
+ kube_statefulset_status_observed_generation{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ !=
+ kube_statefulset_metadata_generation{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeStatefulSetUpdateNotRolledOut | default false) }}
+ - alert: KubeStatefulSetUpdateNotRolledOut
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: StatefulSet {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.statefulset {{`}}`}} update has not been rolled out.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubestatefulsetupdatenotrolledout
+ summary: StatefulSet update has not been rolled out.
+ expr: |-
+ (
+ max without (revision) (
+ kube_statefulset_status_current_revision{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ unless
+ kube_statefulset_status_update_revision{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ )
+ *
+ (
+ kube_statefulset_replicas{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ !=
+ kube_statefulset_status_replicas_updated{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ )
+ ) and (
+ changes(kube_statefulset_status_replicas_updated{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}[5m])
+ ==
+ 0
+ )
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeDaemonSetRolloutStuck | default false) }}
+ - alert: KubeDaemonSetRolloutStuck
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: DaemonSet {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.daemonset {{`}}`}} has not finished or progressed for at least 15 minutes.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubedaemonsetrolloutstuck
+ summary: DaemonSet rollout is stuck.
+ expr: |-
+ (
+ (
+ kube_daemonset_status_current_number_scheduled{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ !=
+ kube_daemonset_status_desired_number_scheduled{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ ) or (
+ kube_daemonset_status_number_misscheduled{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ !=
+ 0
+ ) or (
+ kube_daemonset_status_updated_number_scheduled{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ !=
+ kube_daemonset_status_desired_number_scheduled{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ ) or (
+ kube_daemonset_status_number_available{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ !=
+ kube_daemonset_status_desired_number_scheduled{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ )
+ ) and (
+ changes(kube_daemonset_status_updated_number_scheduled{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}[5m])
+ ==
+ 0
+ )
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeContainerWaiting | default false) }}
+ - alert: KubeContainerWaiting
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: pod/{{`{{`}} $labels.pod {{`}}`}} in namespace {{`{{`}} $labels.namespace {{`}}`}} on container {{`{{`}} $labels.container{{`}}`}} has been in waiting state for longer than 1 hour.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubecontainerwaiting
+ summary: Pod container waiting longer than 1 hour
+ expr: sum by (namespace, pod, container, cluster) (kube_pod_container_status_waiting_reason{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}) > 0
+ for: 1h
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeDaemonSetNotScheduled | default false) }}
+ - alert: KubeDaemonSetNotScheduled
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} $value {{`}}`}} Pods of DaemonSet {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.daemonset {{`}}`}} are not scheduled.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubedaemonsetnotscheduled
+ summary: DaemonSet pods are not scheduled.
+ expr: |-
+ kube_daemonset_status_desired_number_scheduled{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ -
+ kube_daemonset_status_current_number_scheduled{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"} > 0
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeDaemonSetMisScheduled | default false) }}
+ - alert: KubeDaemonSetMisScheduled
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} $value {{`}}`}} Pods of DaemonSet {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.daemonset {{`}}`}} are running where they are not supposed to run.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubedaemonsetmisscheduled
+ summary: DaemonSet pods are misscheduled.
+ expr: kube_daemonset_status_number_misscheduled{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"} > 0
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeJobNotCompleted | default false) }}
+ - alert: KubeJobNotCompleted
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Job {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.job_name {{`}}`}} is taking more than {{`{{`}} "43200" | humanizeDuration {{`}}`}} to complete.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubejobnotcompleted
+ summary: Job did not complete in time
+ expr: |-
+ time() - max by(namespace, job_name, cluster) (kube_job_status_start_time{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ and
+ kube_job_status_active{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"} > 0) > 43200
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeJobFailed | default false) }}
+ - alert: KubeJobFailed
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Job {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.job_name {{`}}`}} failed to complete. Removing failed job after investigation should clear this alert.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubejobfailed
+ summary: Job failed to complete.
+ expr: kube_job_failed{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"} > 0
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeHpaReplicasMismatch | default false) }}
+ - alert: KubeHpaReplicasMismatch
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: HPA {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.horizontalpodautoscaler {{`}}`}} has not matched the desired number of replicas for longer than 15 minutes.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubehpareplicasmismatch
+ summary: HPA has not matched desired number of replicas.
+ expr: |-
+ (kube_horizontalpodautoscaler_status_desired_replicas{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ !=
+ kube_horizontalpodautoscaler_status_current_replicas{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"})
+ and
+ (kube_horizontalpodautoscaler_status_current_replicas{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ >
+ kube_horizontalpodautoscaler_spec_min_replicas{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"})
+ and
+ (kube_horizontalpodautoscaler_status_current_replicas{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ <
+ kube_horizontalpodautoscaler_spec_max_replicas{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"})
+ and
+ changes(kube_horizontalpodautoscaler_status_current_replicas{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}[15m]) == 0
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeHpaMaxedOut | default false) }}
+ - alert: KubeHpaMaxedOut
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: HPA {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.horizontalpodautoscaler {{`}}`}} has been running at max replicas for longer than 15 minutes.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubehpamaxedout
+ summary: HPA is running at max replicas
+ expr: |-
+ kube_horizontalpodautoscaler_status_current_replicas{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ ==
+ kube_horizontalpodautoscaler_spec_max_replicas{job="kube-state-metrics", namespace=~"{{ $targetNamespace }}"}
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-resources.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-resources.yaml
new file mode 100644
index 00000000..5fab8d7a
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-resources.yaml
@@ -0,0 +1,193 @@
+{{- /*
+Generated from 'kubernetes-resources' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubernetesResources }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-resources" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kubernetes-resources
+ rules:
+{{- if not (.Values.defaultRules.disabled.KubeCPUOvercommit | default false) }}
+ - alert: KubeCPUOvercommit
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Cluster has overcommitted CPU resource requests for Pods by {{`{{`}} $value {{`}}`}} CPU shares and cannot tolerate node failure.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubecpuovercommit
+ summary: Cluster has overcommitted CPU resource requests.
+ expr: |-
+ sum(namespace_cpu:kube_pod_container_resource_requests:sum{}) - (sum(kube_node_status_allocatable{resource="cpu"}) - max(kube_node_status_allocatable{resource="cpu"})) > 0
+ and
+ (sum(kube_node_status_allocatable{resource="cpu"}) - max(kube_node_status_allocatable{resource="cpu"})) > 0
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeMemoryOvercommit | default false) }}
+ - alert: KubeMemoryOvercommit
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Cluster has overcommitted memory resource requests for Pods by {{`{{`}} $value | humanize {{`}}`}} bytes and cannot tolerate node failure.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubememoryovercommit
+ summary: Cluster has overcommitted memory resource requests.
+ expr: |-
+ sum(namespace_memory:kube_pod_container_resource_requests:sum{}) - (sum(kube_node_status_allocatable{resource="memory"}) - max(kube_node_status_allocatable{resource="memory"})) > 0
+ and
+ (sum(kube_node_status_allocatable{resource="memory"}) - max(kube_node_status_allocatable{resource="memory"})) > 0
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeCPUQuotaOvercommit | default false) }}
+ - alert: KubeCPUQuotaOvercommit
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Cluster has overcommitted CPU resource requests for Namespaces.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubecpuquotaovercommit
+ summary: Cluster has overcommitted CPU resource requests.
+ expr: |-
+ sum(min without(resource) (kube_resourcequota{job="kube-state-metrics", type="hard", resource=~"(cpu|requests.cpu)"}))
+ /
+ sum(kube_node_status_allocatable{resource="cpu", job="kube-state-metrics"})
+ > 1.5
+ for: 5m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeMemoryQuotaOvercommit | default false) }}
+ - alert: KubeMemoryQuotaOvercommit
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Cluster has overcommitted memory resource requests for Namespaces.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubememoryquotaovercommit
+ summary: Cluster has overcommitted memory resource requests.
+ expr: |-
+ sum(min without(resource) (kube_resourcequota{job="kube-state-metrics", type="hard", resource=~"(memory|requests.memory)"}))
+ /
+ sum(kube_node_status_allocatable{resource="memory", job="kube-state-metrics"})
+ > 1.5
+ for: 5m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeQuotaAlmostFull | default false) }}
+ - alert: KubeQuotaAlmostFull
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Namespace {{`{{`}} $labels.namespace {{`}}`}} is using {{`{{`}} $value | humanizePercentage {{`}}`}} of its {{`{{`}} $labels.resource {{`}}`}} quota.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubequotaalmostfull
+ summary: Namespace quota is going to be full.
+ expr: |-
+ kube_resourcequota{job="kube-state-metrics", type="used"}
+ / ignoring(instance, job, type)
+ (kube_resourcequota{job="kube-state-metrics", type="hard"} > 0)
+ > 0.9 < 1
+ for: 15m
+ labels:
+ severity: info
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeQuotaFullyUsed | default false) }}
+ - alert: KubeQuotaFullyUsed
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Namespace {{`{{`}} $labels.namespace {{`}}`}} is using {{`{{`}} $value | humanizePercentage {{`}}`}} of its {{`{{`}} $labels.resource {{`}}`}} quota.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubequotafullyused
+ summary: Namespace quota is fully used.
+ expr: |-
+ kube_resourcequota{job="kube-state-metrics", type="used"}
+ / ignoring(instance, job, type)
+ (kube_resourcequota{job="kube-state-metrics", type="hard"} > 0)
+ == 1
+ for: 15m
+ labels:
+ severity: info
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeQuotaExceeded | default false) }}
+ - alert: KubeQuotaExceeded
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Namespace {{`{{`}} $labels.namespace {{`}}`}} is using {{`{{`}} $value | humanizePercentage {{`}}`}} of its {{`{{`}} $labels.resource {{`}}`}} quota.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubequotaexceeded
+ summary: Namespace quota has exceeded the limits.
+ expr: |-
+ kube_resourcequota{job="kube-state-metrics", type="used"}
+ / ignoring(instance, job, type)
+ (kube_resourcequota{job="kube-state-metrics", type="hard"} > 0)
+ > 1
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.CPUThrottlingHigh | default false) }}
+ - alert: CPUThrottlingHigh
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} $value | humanizePercentage {{`}}`}} throttling of CPU in namespace {{`{{`}} $labels.namespace {{`}}`}} for container {{`{{`}} $labels.container {{`}}`}} in pod {{`{{`}} $labels.pod {{`}}`}}.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/cputhrottlinghigh
+ summary: Processes experience elevated CPU throttling.
+ expr: |-
+ sum(increase(container_cpu_cfs_throttled_periods_total{container!="", }[5m])) by (container, pod, namespace)
+ /
+ sum(increase(container_cpu_cfs_periods_total{}[5m])) by (container, pod, namespace)
+ > ( 25 / 100 )
+ for: 15m
+ labels:
+ severity: info
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-storage.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-storage.yaml
new file mode 100644
index 00000000..fd193398
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-storage.yaml
@@ -0,0 +1,161 @@
+{{- /*
+Generated from 'kubernetes-storage' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubernetesStorage }}
+{{- $targetNamespace := .Values.defaultRules.appNamespacesTarget }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-storage" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kubernetes-storage
+ rules:
+{{- if not (.Values.defaultRules.disabled.KubePersistentVolumeFillingUp | default false) }}
+ - alert: KubePersistentVolumeFillingUp
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: The PersistentVolume claimed by {{`{{`}} $labels.persistentvolumeclaim {{`}}`}} in Namespace {{`{{`}} $labels.namespace {{`}}`}} is only {{`{{`}} $value | humanizePercentage {{`}}`}} free.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepersistentvolumefillingup
+ summary: PersistentVolume is filling up.
+ expr: |-
+ (
+ kubelet_volume_stats_available_bytes{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"}
+ /
+ kubelet_volume_stats_capacity_bytes{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"}
+ ) < 0.03
+ and
+ kubelet_volume_stats_used_bytes{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} > 0
+ unless on(namespace, persistentvolumeclaim)
+ kube_persistentvolumeclaim_access_mode{ access_mode="ReadOnlyMany"} == 1
+ unless on(namespace, persistentvolumeclaim)
+ kube_persistentvolumeclaim_labels{label_excluded_from_alerts="true"} == 1
+ for: 1m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubePersistentVolumeFillingUp | default false) }}
+ - alert: KubePersistentVolumeFillingUp
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Based on recent sampling, the PersistentVolume claimed by {{`{{`}} $labels.persistentvolumeclaim {{`}}`}} in Namespace {{`{{`}} $labels.namespace {{`}}`}} is expected to fill up within four days. Currently {{`{{`}} $value | humanizePercentage {{`}}`}} is available.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepersistentvolumefillingup
+ summary: PersistentVolume is filling up.
+ expr: |-
+ (
+ kubelet_volume_stats_available_bytes{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"}
+ /
+ kubelet_volume_stats_capacity_bytes{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"}
+ ) < 0.15
+ and
+ kubelet_volume_stats_used_bytes{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} > 0
+ and
+ predict_linear(kubelet_volume_stats_available_bytes{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"}[6h], 4 * 24 * 3600) < 0
+ unless on(namespace, persistentvolumeclaim)
+ kube_persistentvolumeclaim_access_mode{ access_mode="ReadOnlyMany"} == 1
+ unless on(namespace, persistentvolumeclaim)
+ kube_persistentvolumeclaim_labels{label_excluded_from_alerts="true"} == 1
+ for: 1h
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubePersistentVolumeInodesFillingUp | default false) }}
+ - alert: KubePersistentVolumeInodesFillingUp
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: The PersistentVolume claimed by {{`{{`}} $labels.persistentvolumeclaim {{`}}`}} in Namespace {{`{{`}} $labels.namespace {{`}}`}} only has {{`{{`}} $value | humanizePercentage {{`}}`}} free inodes.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepersistentvolumeinodesfillingup
+ summary: PersistentVolumeInodes are filling up.
+ expr: |-
+ (
+ kubelet_volume_stats_inodes_free{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"}
+ /
+ kubelet_volume_stats_inodes{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"}
+ ) < 0.03
+ and
+ kubelet_volume_stats_inodes_used{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} > 0
+ unless on(namespace, persistentvolumeclaim)
+ kube_persistentvolumeclaim_access_mode{ access_mode="ReadOnlyMany"} == 1
+ unless on(namespace, persistentvolumeclaim)
+ kube_persistentvolumeclaim_labels{label_excluded_from_alerts="true"} == 1
+ for: 1m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubePersistentVolumeInodesFillingUp | default false) }}
+ - alert: KubePersistentVolumeInodesFillingUp
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Based on recent sampling, the PersistentVolume claimed by {{`{{`}} $labels.persistentvolumeclaim {{`}}`}} in Namespace {{`{{`}} $labels.namespace {{`}}`}} is expected to run out of inodes within four days. Currently {{`{{`}} $value | humanizePercentage {{`}}`}} of its inodes are free.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepersistentvolumeinodesfillingup
+ summary: PersistentVolumeInodes are filling up.
+ expr: |-
+ (
+ kubelet_volume_stats_inodes_free{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"}
+ /
+ kubelet_volume_stats_inodes{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"}
+ ) < 0.15
+ and
+ kubelet_volume_stats_inodes_used{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} > 0
+ and
+ predict_linear(kubelet_volume_stats_inodes_free{job="kubelet", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"}[6h], 4 * 24 * 3600) < 0
+ unless on(namespace, persistentvolumeclaim)
+ kube_persistentvolumeclaim_access_mode{ access_mode="ReadOnlyMany"} == 1
+ unless on(namespace, persistentvolumeclaim)
+ kube_persistentvolumeclaim_labels{label_excluded_from_alerts="true"} == 1
+ for: 1h
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubePersistentVolumeErrors | default false) }}
+ - alert: KubePersistentVolumeErrors
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: The persistent volume {{`{{`}} $labels.persistentvolume {{`}}`}} has status {{`{{`}} $labels.phase {{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepersistentvolumeerrors
+ summary: PersistentVolume is having issues with provisioning.
+ expr: kube_persistentvolume_status_phase{phase=~"Failed|Pending",job="kube-state-metrics"} > 0
+ for: 5m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-apiserver.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-apiserver.yaml
new file mode 100644
index 00000000..aff07d6a
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-apiserver.yaml
@@ -0,0 +1,128 @@
+{{- /*
+Generated from 'kubernetes-system-apiserver' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubernetesSystem }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-system-apiserver" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kubernetes-system-apiserver
+ rules:
+{{- if not (.Values.defaultRules.disabled.KubeClientCertificateExpiration | default false) }}
+ - alert: KubeClientCertificateExpiration
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: A client certificate used to authenticate to kubernetes apiserver is expiring in less than 7.0 days.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeclientcertificateexpiration
+ summary: Client certificate is about to expire.
+ expr: apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and on(job) histogram_quantile(0.01, sum by (job, le) (rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) < 604800
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeClientCertificateExpiration | default false) }}
+ - alert: KubeClientCertificateExpiration
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: A client certificate used to authenticate to kubernetes apiserver is expiring in less than 24.0 hours.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeclientcertificateexpiration
+ summary: Client certificate is about to expire.
+ expr: apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and on(job) histogram_quantile(0.01, sum by (job, le) (rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) < 86400
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeAggregatedAPIErrors | default false) }}
+ - alert: KubeAggregatedAPIErrors
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Kubernetes aggregated API {{`{{`}} $labels.name {{`}}`}}/{{`{{`}} $labels.namespace {{`}}`}} has reported errors. It has appeared unavailable {{`{{`}} $value | humanize {{`}}`}} times averaged over the past 10m.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeaggregatedapierrors
+ summary: Kubernetes aggregated API has reported errors.
+ expr: sum by(name, namespace, cluster)(increase(aggregator_unavailable_apiservice_total[10m])) > 4
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeAggregatedAPIDown | default false) }}
+ - alert: KubeAggregatedAPIDown
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Kubernetes aggregated API {{`{{`}} $labels.name {{`}}`}}/{{`{{`}} $labels.namespace {{`}}`}} has been only {{`{{`}} $value | humanize {{`}}`}}% available over the last 10m.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeaggregatedapidown
+ summary: Kubernetes aggregated API is down.
+ expr: (1 - max by(name, namespace, cluster)(avg_over_time(aggregator_unavailable_apiservice[10m]))) * 100 < 85
+ for: 5m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if .Values.kubeApiServer.enabled }}
+{{- if not (.Values.defaultRules.disabled.KubeAPIDown | default false) }}
+ - alert: KubeAPIDown
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: KubeAPI has disappeared from Prometheus target discovery.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeapidown
+ summary: Target disappeared from Prometheus target discovery.
+ expr: absent(up{job="apiserver"} == 1)
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeAPITerminatedRequests | default false) }}
+ - alert: KubeAPITerminatedRequests
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: The kubernetes apiserver has terminated {{`{{`}} $value | humanizePercentage {{`}}`}} of its incoming requests.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeapiterminatedrequests
+ summary: The kubernetes apiserver has terminated {{`{{`}} $value | humanizePercentage {{`}}`}} of its incoming requests.
+ expr: sum(rate(apiserver_request_terminations_total{job="apiserver"}[10m])) / ( sum(rate(apiserver_request_total{job="apiserver"}[10m])) + sum(rate(apiserver_request_terminations_total{job="apiserver"}[10m])) ) > 0.20
+ for: 5m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-controller-manager.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-controller-manager.yaml
new file mode 100644
index 00000000..c423fb81
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-controller-manager.yaml
@@ -0,0 +1,46 @@
+{{- /*
+Generated from 'kubernetes-system-controller-manager' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeControllerManager.enabled .Values.defaultRules.rules.kubeControllerManager }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-system-controller-manager" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kubernetes-system-controller-manager
+ rules:
+{{- if .Values.kubeControllerManager.enabled }}
+{{- if not (.Values.defaultRules.disabled.KubeControllerManagerDown | default false) }}
+ - alert: KubeControllerManagerDown
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: KubeControllerManager has disappeared from Prometheus target discovery.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubecontrollermanagerdown
+ summary: Target disappeared from Prometheus target discovery.
+ expr: absent(up{job="kube-controller-manager"} == 1)
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-kube-proxy.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-kube-proxy.yaml
new file mode 100644
index 00000000..8082fdc0
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-kube-proxy.yaml
@@ -0,0 +1,44 @@
+{{- /*
+Generated from 'kubernetes-system-kube-proxy' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeProxy.enabled .Values.defaultRules.rules.kubeProxy }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-system-kube-proxy" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kubernetes-system-kube-proxy
+ rules:
+{{- if not (.Values.defaultRules.disabled.KubeProxyDown | default false) }}
+ - alert: KubeProxyDown
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: KubeProxy has disappeared from Prometheus target discovery.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeproxydown
+ summary: Target disappeared from Prometheus target discovery.
+ expr: absent(up{job="kube-proxy"} == 1)
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-kubelet.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-kubelet.yaml
new file mode 100644
index 00000000..fe558cf2
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-kubelet.yaml
@@ -0,0 +1,253 @@
+{{- /*
+Generated from 'kubernetes-system-kubelet' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubernetesSystem }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-system-kubelet" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kubernetes-system-kubelet
+ rules:
+{{- if not (.Values.defaultRules.disabled.KubeNodeNotReady | default false) }}
+ - alert: KubeNodeNotReady
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} $labels.node {{`}}`}} has been unready for more than 15 minutes.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubenodenotready
+ summary: Node is not ready.
+ expr: kube_node_status_condition{job="kube-state-metrics",condition="Ready",status="true"} == 0
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeNodeUnreachable | default false) }}
+ - alert: KubeNodeUnreachable
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} $labels.node {{`}}`}} is unreachable and some workloads may be rescheduled.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubenodeunreachable
+ summary: Node is unreachable.
+ expr: (kube_node_spec_taint{job="kube-state-metrics",key="node.kubernetes.io/unreachable",effect="NoSchedule"} unless ignoring(key,value) kube_node_spec_taint{job="kube-state-metrics",key=~"ToBeDeletedByClusterAutoscaler|cloud.google.com/impending-node-termination|aws-node-termination-handler/spot-itn"}) == 1
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeletTooManyPods | default false) }}
+ - alert: KubeletTooManyPods
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Kubelet '{{`{{`}} $labels.node {{`}}`}}' is running at {{`{{`}} $value | humanizePercentage {{`}}`}} of its Pod capacity.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubelettoomanypods
+ summary: Kubelet is running at capacity.
+ expr: |-
+ count by(cluster, node) (
+ (kube_pod_status_phase{job="kube-state-metrics",phase="Running"} == 1) * on(instance,pod,namespace,cluster) group_left(node) topk by(instance,pod,namespace,cluster) (1, kube_pod_info{job="kube-state-metrics"})
+ )
+ /
+ max by(cluster, node) (
+ kube_node_status_capacity{job="kube-state-metrics",resource="pods"} != 1
+ ) > 0.95
+ for: 15m
+ labels:
+ severity: info
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeNodeReadinessFlapping | default false) }}
+ - alert: KubeNodeReadinessFlapping
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: The readiness status of node {{`{{`}} $labels.node {{`}}`}} has changed {{`{{`}} $value {{`}}`}} times in the last 15 minutes.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubenodereadinessflapping
+ summary: Node readiness status is flapping.
+ expr: sum(changes(kube_node_status_condition{status="true",condition="Ready"}[15m])) by (cluster, node) > 2
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeletPlegDurationHigh | default false) }}
+ - alert: KubeletPlegDurationHigh
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: The Kubelet Pod Lifecycle Event Generator has a 99th percentile duration of {{`{{`}} $value {{`}}`}} seconds on node {{`{{`}} $labels.node {{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletplegdurationhigh
+ summary: Kubelet Pod Lifecycle Event Generator is taking too long to relist.
+ expr: node_quantile:kubelet_pleg_relist_duration_seconds:histogram_quantile{quantile="0.99"} >= 10
+ for: 5m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeletPodStartUpLatencyHigh | default false) }}
+ - alert: KubeletPodStartUpLatencyHigh
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Kubelet Pod startup 99th percentile latency is {{`{{`}} $value {{`}}`}} seconds on node {{`{{`}} $labels.node {{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletpodstartuplatencyhigh
+ summary: Kubelet Pod startup latency is too high.
+ expr: histogram_quantile(0.99, sum(rate(kubelet_pod_worker_duration_seconds_bucket{job="kubelet", metrics_path="/metrics"}[5m])) by (cluster, instance, le)) * on(cluster, instance) group_left(node) kubelet_node_name{job="kubelet", metrics_path="/metrics"} > 60
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeletClientCertificateExpiration | default false) }}
+ - alert: KubeletClientCertificateExpiration
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Client certificate for Kubelet on node {{`{{`}} $labels.node {{`}}`}} expires in {{`{{`}} $value | humanizeDuration {{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletclientcertificateexpiration
+ summary: Kubelet client certificate is about to expire.
+ expr: kubelet_certificate_manager_client_ttl_seconds < 604800
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeletClientCertificateExpiration | default false) }}
+ - alert: KubeletClientCertificateExpiration
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Client certificate for Kubelet on node {{`{{`}} $labels.node {{`}}`}} expires in {{`{{`}} $value | humanizeDuration {{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletclientcertificateexpiration
+ summary: Kubelet client certificate is about to expire.
+ expr: kubelet_certificate_manager_client_ttl_seconds < 86400
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeletServerCertificateExpiration | default false) }}
+ - alert: KubeletServerCertificateExpiration
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Server certificate for Kubelet on node {{`{{`}} $labels.node {{`}}`}} expires in {{`{{`}} $value | humanizeDuration {{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletservercertificateexpiration
+ summary: Kubelet server certificate is about to expire.
+ expr: kubelet_certificate_manager_server_ttl_seconds < 604800
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeletServerCertificateExpiration | default false) }}
+ - alert: KubeletServerCertificateExpiration
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Server certificate for Kubelet on node {{`{{`}} $labels.node {{`}}`}} expires in {{`{{`}} $value | humanizeDuration {{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletservercertificateexpiration
+ summary: Kubelet server certificate is about to expire.
+ expr: kubelet_certificate_manager_server_ttl_seconds < 86400
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeletClientCertificateRenewalErrors | default false) }}
+ - alert: KubeletClientCertificateRenewalErrors
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Kubelet on node {{`{{`}} $labels.node {{`}}`}} has failed to renew its client certificate ({{`{{`}} $value | humanize {{`}}`}} errors in the last 5 minutes).
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletclientcertificaterenewalerrors
+ summary: Kubelet has failed to renew its client certificate.
+ expr: increase(kubelet_certificate_manager_client_expiration_renew_errors[5m]) > 0
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeletServerCertificateRenewalErrors | default false) }}
+ - alert: KubeletServerCertificateRenewalErrors
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Kubelet on node {{`{{`}} $labels.node {{`}}`}} has failed to renew its server certificate ({{`{{`}} $value | humanize {{`}}`}} errors in the last 5 minutes).
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletservercertificaterenewalerrors
+ summary: Kubelet has failed to renew its server certificate.
+ expr: increase(kubelet_server_expiration_renew_errors[5m]) > 0
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if .Values.prometheusOperator.kubeletService.enabled }}
+{{- if not (.Values.defaultRules.disabled.KubeletDown | default false) }}
+ - alert: KubeletDown
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Kubelet has disappeared from Prometheus target discovery.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletdown
+ summary: Target disappeared from Prometheus target discovery.
+ expr: absent(up{job="kubelet", metrics_path="/metrics"} == 1)
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-scheduler.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-scheduler.yaml
new file mode 100644
index 00000000..676f2ca4
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-scheduler.yaml
@@ -0,0 +1,46 @@
+{{- /*
+Generated from 'kubernetes-system-scheduler' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeScheduler.enabled .Values.defaultRules.rules.kubeScheduler }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-system-scheduler" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kubernetes-system-scheduler
+ rules:
+{{- if .Values.kubeScheduler.enabled }}
+{{- if not (.Values.defaultRules.disabled.KubeSchedulerDown | default false) }}
+ - alert: KubeSchedulerDown
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: KubeScheduler has disappeared from Prometheus target discovery.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeschedulerdown
+ summary: Target disappeared from Prometheus target discovery.
+ expr: absent(up{job="kube-scheduler"} == 1)
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system.yaml
new file mode 100644
index 00000000..32605926
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system.yaml
@@ -0,0 +1,65 @@
+{{- /*
+Generated from 'kubernetes-system' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubernetesSystem }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-system" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: kubernetes-system
+ rules:
+{{- if not (.Values.defaultRules.disabled.KubeVersionMismatch | default false) }}
+ - alert: KubeVersionMismatch
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: There are {{`{{`}} $value {{`}}`}} different semantic versions of Kubernetes components running.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeversionmismatch
+ summary: Different semantic versions of Kubernetes components running.
+ expr: count by (cluster) (count by (git_version, cluster) (label_replace(kubernetes_build_info{job!~"kube-dns|coredns"},"git_version","$1","git_version","(v[0-9]*.[0-9]*).*"))) > 1
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.KubeClientErrors | default false) }}
+ - alert: KubeClientErrors
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Kubernetes API server client '{{`{{`}} $labels.job {{`}}`}}/{{`{{`}} $labels.instance {{`}}`}}' is experiencing {{`{{`}} $value | humanizePercentage {{`}}`}} errors.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeclienterrors
+ summary: Kubernetes API server client is experiencing errors.
+ expr: |-
+ (sum(rate(rest_client_requests_total{code=~"5.."}[5m])) by (cluster, instance, job, namespace)
+ /
+ sum(rate(rest_client_requests_total[5m])) by (cluster, instance, job, namespace))
+ > 0.01
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/node-exporter.rules.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/node-exporter.rules.yaml
new file mode 100644
index 00000000..c3cfe36c
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/node-exporter.rules.yaml
@@ -0,0 +1,89 @@
+{{- /*
+Generated from 'node-exporter.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/nodeExporter-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.nodeExporterRecording }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "node-exporter.rules" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: node-exporter.rules
+ rules:
+ - expr: |-
+ count without (cpu, mode) (
+ node_cpu_seconds_total{job="node-exporter",mode="idle"}
+ )
+ record: instance:node_num_cpu:sum
+ - expr: |-
+ 1 - avg without (cpu) (
+ sum without (mode) (rate(node_cpu_seconds_total{job="node-exporter", mode=~"idle|iowait|steal"}[5m]))
+ )
+ record: instance:node_cpu_utilisation:rate5m
+ - expr: |-
+ (
+ node_load1{job="node-exporter"}
+ /
+ instance:node_num_cpu:sum{job="node-exporter"}
+ )
+ record: instance:node_load1_per_cpu:ratio
+ - expr: |-
+ 1 - (
+ (
+ node_memory_MemAvailable_bytes{job="node-exporter"}
+ or
+ (
+ node_memory_Buffers_bytes{job="node-exporter"}
+ +
+ node_memory_Cached_bytes{job="node-exporter"}
+ +
+ node_memory_MemFree_bytes{job="node-exporter"}
+ +
+ node_memory_Slab_bytes{job="node-exporter"}
+ )
+ )
+ /
+ node_memory_MemTotal_bytes{job="node-exporter"}
+ )
+ record: instance:node_memory_utilisation:ratio
+ - expr: rate(node_vmstat_pgmajfault{job="node-exporter"}[5m])
+ record: instance:node_vmstat_pgmajfault:rate5m
+ - expr: rate(node_disk_io_time_seconds_total{job="node-exporter", device=~"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)"}[5m])
+ record: instance_device:node_disk_io_time_seconds:rate5m
+ - expr: rate(node_disk_io_time_weighted_seconds_total{job="node-exporter", device=~"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)"}[5m])
+ record: instance_device:node_disk_io_time_weighted_seconds:rate5m
+ - expr: |-
+ sum without (device) (
+ rate(node_network_receive_bytes_total{job="node-exporter", device!="lo"}[5m])
+ )
+ record: instance:node_network_receive_bytes_excluding_lo:rate5m
+ - expr: |-
+ sum without (device) (
+ rate(node_network_transmit_bytes_total{job="node-exporter", device!="lo"}[5m])
+ )
+ record: instance:node_network_transmit_bytes_excluding_lo:rate5m
+ - expr: |-
+ sum without (device) (
+ rate(node_network_receive_drop_total{job="node-exporter", device!="lo"}[5m])
+ )
+ record: instance:node_network_receive_drop_excluding_lo:rate5m
+ - expr: |-
+ sum without (device) (
+ rate(node_network_transmit_drop_total{job="node-exporter", device!="lo"}[5m])
+ )
+ record: instance:node_network_transmit_drop_excluding_lo:rate5m
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/node-exporter.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/node-exporter.yaml
new file mode 100644
index 00000000..2fa7e28d
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/node-exporter.yaml
@@ -0,0 +1,398 @@
+{{- /*
+Generated from 'node-exporter' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/nodeExporter-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.nodeExporterAlerting }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "node-exporter" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: node-exporter
+ rules:
+{{- if not (.Values.defaultRules.disabled.NodeFilesystemSpaceFillingUp | default false) }}
+ - alert: NodeFilesystemSpaceFillingUp
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Filesystem on {{`{{`}} $labels.device {{`}}`}} at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available space left and is filling up.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemspacefillingup
+ summary: Filesystem is predicted to run out of space within the next 24 hours.
+ expr: |-
+ (
+ node_filesystem_avail_bytes{job="node-exporter",fstype!=""} / node_filesystem_size_bytes{job="node-exporter",fstype!=""} * 100 < 15
+ and
+ predict_linear(node_filesystem_avail_bytes{job="node-exporter",fstype!=""}[6h], 24*60*60) < 0
+ and
+ node_filesystem_readonly{job="node-exporter",fstype!=""} == 0
+ )
+ for: 1h
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeFilesystemSpaceFillingUp | default false) }}
+ - alert: NodeFilesystemSpaceFillingUp
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Filesystem on {{`{{`}} $labels.device {{`}}`}} at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available space left and is filling up fast.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemspacefillingup
+ summary: Filesystem is predicted to run out of space within the next 4 hours.
+ expr: |-
+ (
+ node_filesystem_avail_bytes{job="node-exporter",fstype!=""} / node_filesystem_size_bytes{job="node-exporter",fstype!=""} * 100 < 10
+ and
+ predict_linear(node_filesystem_avail_bytes{job="node-exporter",fstype!=""}[6h], 4*60*60) < 0
+ and
+ node_filesystem_readonly{job="node-exporter",fstype!=""} == 0
+ )
+ for: 1h
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeFilesystemAlmostOutOfSpace | default false) }}
+ - alert: NodeFilesystemAlmostOutOfSpace
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Filesystem on {{`{{`}} $labels.device {{`}}`}} at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available space left.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemalmostoutofspace
+ summary: Filesystem has less than 5% space left.
+ expr: |-
+ (
+ node_filesystem_avail_bytes{job="node-exporter",fstype!=""} / node_filesystem_size_bytes{job="node-exporter",fstype!=""} * 100 < 5
+ and
+ node_filesystem_readonly{job="node-exporter",fstype!=""} == 0
+ )
+ for: 30m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeFilesystemAlmostOutOfSpace | default false) }}
+ - alert: NodeFilesystemAlmostOutOfSpace
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Filesystem on {{`{{`}} $labels.device {{`}}`}} at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available space left.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemalmostoutofspace
+ summary: Filesystem has less than 3% space left.
+ expr: |-
+ (
+ node_filesystem_avail_bytes{job="node-exporter",fstype!=""} / node_filesystem_size_bytes{job="node-exporter",fstype!=""} * 100 < 3
+ and
+ node_filesystem_readonly{job="node-exporter",fstype!=""} == 0
+ )
+ for: 30m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeFilesystemFilesFillingUp | default false) }}
+ - alert: NodeFilesystemFilesFillingUp
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Filesystem on {{`{{`}} $labels.device {{`}}`}} at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available inodes left and is filling up.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemfilesfillingup
+ summary: Filesystem is predicted to run out of inodes within the next 24 hours.
+ expr: |-
+ (
+ node_filesystem_files_free{job="node-exporter",fstype!=""} / node_filesystem_files{job="node-exporter",fstype!=""} * 100 < 40
+ and
+ predict_linear(node_filesystem_files_free{job="node-exporter",fstype!=""}[6h], 24*60*60) < 0
+ and
+ node_filesystem_readonly{job="node-exporter",fstype!=""} == 0
+ )
+ for: 1h
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeFilesystemFilesFillingUp | default false) }}
+ - alert: NodeFilesystemFilesFillingUp
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Filesystem on {{`{{`}} $labels.device {{`}}`}} at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available inodes left and is filling up fast.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemfilesfillingup
+ summary: Filesystem is predicted to run out of inodes within the next 4 hours.
+ expr: |-
+ (
+ node_filesystem_files_free{job="node-exporter",fstype!=""} / node_filesystem_files{job="node-exporter",fstype!=""} * 100 < 20
+ and
+ predict_linear(node_filesystem_files_free{job="node-exporter",fstype!=""}[6h], 4*60*60) < 0
+ and
+ node_filesystem_readonly{job="node-exporter",fstype!=""} == 0
+ )
+ for: 1h
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeFilesystemAlmostOutOfFiles | default false) }}
+ - alert: NodeFilesystemAlmostOutOfFiles
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Filesystem on {{`{{`}} $labels.device {{`}}`}} at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available inodes left.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemalmostoutoffiles
+ summary: Filesystem has less than 5% inodes left.
+ expr: |-
+ (
+ node_filesystem_files_free{job="node-exporter",fstype!=""} / node_filesystem_files{job="node-exporter",fstype!=""} * 100 < 5
+ and
+ node_filesystem_readonly{job="node-exporter",fstype!=""} == 0
+ )
+ for: 1h
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeFilesystemAlmostOutOfFiles | default false) }}
+ - alert: NodeFilesystemAlmostOutOfFiles
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Filesystem on {{`{{`}} $labels.device {{`}}`}} at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available inodes left.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemalmostoutoffiles
+ summary: Filesystem has less than 3% inodes left.
+ expr: |-
+ (
+ node_filesystem_files_free{job="node-exporter",fstype!=""} / node_filesystem_files{job="node-exporter",fstype!=""} * 100 < 3
+ and
+ node_filesystem_readonly{job="node-exporter",fstype!=""} == 0
+ )
+ for: 1h
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeNetworkReceiveErrs | default false) }}
+ - alert: NodeNetworkReceiveErrs
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} $labels.instance {{`}}`}} interface {{`{{`}} $labels.device {{`}}`}} has encountered {{`{{`}} printf "%.0f" $value {{`}}`}} receive errors in the last two minutes.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodenetworkreceiveerrs
+ summary: Network interface is reporting many receive errors.
+ expr: rate(node_network_receive_errs_total[2m]) / rate(node_network_receive_packets_total[2m]) > 0.01
+ for: 1h
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeNetworkTransmitErrs | default false) }}
+ - alert: NodeNetworkTransmitErrs
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} $labels.instance {{`}}`}} interface {{`{{`}} $labels.device {{`}}`}} has encountered {{`{{`}} printf "%.0f" $value {{`}}`}} transmit errors in the last two minutes.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodenetworktransmiterrs
+ summary: Network interface is reporting many transmit errors.
+ expr: rate(node_network_transmit_errs_total[2m]) / rate(node_network_transmit_packets_total[2m]) > 0.01
+ for: 1h
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeHighNumberConntrackEntriesUsed | default false) }}
+ - alert: NodeHighNumberConntrackEntriesUsed
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} $value | humanizePercentage {{`}}`}} of conntrack entries are used.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodehighnumberconntrackentriesused
+ summary: Number of conntrack are getting close to the limit.
+ expr: (node_nf_conntrack_entries / node_nf_conntrack_entries_limit) > 0.75
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeTextFileCollectorScrapeError | default false) }}
+ - alert: NodeTextFileCollectorScrapeError
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Node Exporter text file collector failed to scrape.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodetextfilecollectorscrapeerror
+ summary: Node Exporter text file collector failed to scrape.
+ expr: node_textfile_scrape_error{job="node-exporter"} == 1
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeClockSkewDetected | default false) }}
+ - alert: NodeClockSkewDetected
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Clock on {{`{{`}} $labels.instance {{`}}`}} is out of sync by more than 300s. Ensure NTP is configured correctly on this host.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodeclockskewdetected
+ summary: Clock skew detected.
+ expr: |-
+ (
+ node_timex_offset_seconds{job="node-exporter"} > 0.05
+ and
+ deriv(node_timex_offset_seconds{job="node-exporter"}[5m]) >= 0
+ )
+ or
+ (
+ node_timex_offset_seconds{job="node-exporter"} < -0.05
+ and
+ deriv(node_timex_offset_seconds{job="node-exporter"}[5m]) <= 0
+ )
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeClockNotSynchronising | default false) }}
+ - alert: NodeClockNotSynchronising
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Clock on {{`{{`}} $labels.instance {{`}}`}} is not synchronising. Ensure NTP is configured on this host.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodeclocknotsynchronising
+ summary: Clock not synchronising.
+ expr: |-
+ min_over_time(node_timex_sync_status{job="node-exporter"}[5m]) == 0
+ and
+ node_timex_maxerror_seconds{job="node-exporter"} >= 16
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeRAIDDegraded | default false) }}
+ - alert: NodeRAIDDegraded
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: RAID array '{{`{{`}} $labels.device {{`}}`}}' on {{`{{`}} $labels.instance {{`}}`}} is in degraded state due to one or more disks failures. Number of spare drives is insufficient to fix issue automatically.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/noderaiddegraded
+ summary: RAID Array is degraded
+ expr: node_md_disks_required{job="node-exporter",device=~"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)"} - ignoring (state) (node_md_disks{state="active",job="node-exporter",device=~"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)"}) > 0
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeRAIDDiskFailure | default false) }}
+ - alert: NodeRAIDDiskFailure
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: At least one device in RAID array on {{`{{`}} $labels.instance {{`}}`}} failed. Array '{{`{{`}} $labels.device {{`}}`}}' needs attention and possibly a disk swap.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/noderaiddiskfailure
+ summary: Failed device in RAID array
+ expr: node_md_disks{state="failed",job="node-exporter",device=~"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|dasd.+)"} > 0
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeFileDescriptorLimit | default false) }}
+ - alert: NodeFileDescriptorLimit
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: File descriptors limit at {{`{{`}} $labels.instance {{`}}`}} is currently at {{`{{`}} printf "%.2f" $value {{`}}`}}%.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefiledescriptorlimit
+ summary: Kernel is predicted to exhaust file descriptors limit soon.
+ expr: |-
+ (
+ node_filefd_allocated{job="node-exporter"} * 100 / node_filefd_maximum{job="node-exporter"} > 70
+ )
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.NodeFileDescriptorLimit | default false) }}
+ - alert: NodeFileDescriptorLimit
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: File descriptors limit at {{`{{`}} $labels.instance {{`}}`}} is currently at {{`{{`}} printf "%.2f" $value {{`}}`}}%.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefiledescriptorlimit
+ summary: Kernel is predicted to exhaust file descriptors limit soon.
+ expr: |-
+ (
+ node_filefd_allocated{job="node-exporter"} * 100 / node_filefd_maximum{job="node-exporter"} > 90
+ )
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/node-network.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/node-network.yaml
new file mode 100644
index 00000000..93209734
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/node-network.yaml
@@ -0,0 +1,44 @@
+{{- /*
+Generated from 'node-network' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubePrometheus-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.network }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "node-network" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: node-network
+ rules:
+{{- if not (.Values.defaultRules.disabled.NodeNetworkInterfaceFlapping | default false) }}
+ - alert: NodeNetworkInterfaceFlapping
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Network interface "{{`{{`}} $labels.device {{`}}`}}" changing its up status often on node-exporter {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.pod {{`}}`}}
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/general/nodenetworkinterfaceflapping
+ summary: Network interface is often changing its status
+ expr: changes(node_network_up{job="node-exporter",device!~"veth.+"}[2m]) > 2
+ for: 2m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/node.rules.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/node.rules.yaml
new file mode 100644
index 00000000..4f8da294
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/node.rules.yaml
@@ -0,0 +1,55 @@
+{{- /*
+Generated from 'node.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.node }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "node.rules" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: node.rules
+ rules:
+ - expr: |-
+ topk by(cluster, namespace, pod) (1,
+ max by (cluster, node, namespace, pod) (
+ label_replace(kube_pod_info{job="kube-state-metrics",node!=""}, "pod", "$1", "pod", "(.*)")
+ ))
+ record: 'node_namespace_pod:kube_pod_info:'
+ - expr: |-
+ count by (cluster, node) (sum by (node, cpu) (
+ node_cpu_seconds_total{job="node-exporter"}
+ * on (namespace, pod) group_left(node)
+ topk by(namespace, pod) (1, node_namespace_pod:kube_pod_info:)
+ ))
+ record: node:node_num_cpu:sum
+ - expr: |-
+ sum(
+ node_memory_MemAvailable_bytes{job="node-exporter"} or
+ (
+ node_memory_Buffers_bytes{job="node-exporter"} +
+ node_memory_Cached_bytes{job="node-exporter"} +
+ node_memory_MemFree_bytes{job="node-exporter"} +
+ node_memory_Slab_bytes{job="node-exporter"}
+ )
+ ) by (cluster)
+ record: :node_memory_MemAvailable_bytes:sum
+ - expr: |-
+ sum(rate(node_cpu_seconds_total{job="node-exporter",mode!="idle",mode!="iowait",mode!="steal"}[5m])) /
+ count(sum(node_cpu_seconds_total{job="node-exporter"}) by (cluster, instance, cpu))
+ record: cluster:node_cpu:ratio_rate5m
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/prometheus-operator.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/prometheus-operator.yaml
new file mode 100644
index 00000000..1c6b5c5d
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/prometheus-operator.yaml
@@ -0,0 +1,148 @@
+{{- /*
+Generated from 'prometheus-operator' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/prometheusOperator-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.prometheusOperator }}
+{{- $operatorJob := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "operator" }}
+{{- $namespace := printf "%s" (include "kube-prometheus-stack.namespace" .) }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "prometheus-operator" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: prometheus-operator
+ rules:
+{{- if not (.Values.defaultRules.disabled.PrometheusOperatorListErrors | default false) }}
+ - alert: PrometheusOperatorListErrors
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Errors while performing List operations in controller {{`{{`}}$labels.controller{{`}}`}} in {{`{{`}}$labels.namespace{{`}}`}} namespace.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatorlisterrors
+ summary: Errors while performing list operations in controller.
+ expr: (sum by (controller,namespace) (rate(prometheus_operator_list_operations_failed_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[10m])) / sum by (controller,namespace) (rate(prometheus_operator_list_operations_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[10m]))) > 0.4
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusOperatorWatchErrors | default false) }}
+ - alert: PrometheusOperatorWatchErrors
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Errors while performing watch operations in controller {{`{{`}}$labels.controller{{`}}`}} in {{`{{`}}$labels.namespace{{`}}`}} namespace.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatorwatcherrors
+ summary: Errors while performing watch operations in controller.
+ expr: (sum by (controller,namespace) (rate(prometheus_operator_watch_operations_failed_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m])) / sum by (controller,namespace) (rate(prometheus_operator_watch_operations_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]))) > 0.4
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusOperatorSyncFailed | default false) }}
+ - alert: PrometheusOperatorSyncFailed
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Controller {{`{{`}} $labels.controller {{`}}`}} in {{`{{`}} $labels.namespace {{`}}`}} namespace fails to reconcile {{`{{`}} $value {{`}}`}} objects.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatorsyncfailed
+ summary: Last controller reconciliation failed
+ expr: min_over_time(prometheus_operator_syncs{status="failed",job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]) > 0
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusOperatorReconcileErrors | default false) }}
+ - alert: PrometheusOperatorReconcileErrors
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} $value | humanizePercentage {{`}}`}} of reconciling operations failed for {{`{{`}} $labels.controller {{`}}`}} controller in {{`{{`}} $labels.namespace {{`}}`}} namespace.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatorreconcileerrors
+ summary: Errors while reconciling controller.
+ expr: (sum by (controller,namespace) (rate(prometheus_operator_reconcile_errors_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]))) / (sum by (controller,namespace) (rate(prometheus_operator_reconcile_operations_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]))) > 0.1
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusOperatorNodeLookupErrors | default false) }}
+ - alert: PrometheusOperatorNodeLookupErrors
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Errors while reconciling Prometheus in {{`{{`}} $labels.namespace {{`}}`}} Namespace.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatornodelookuperrors
+ summary: Errors while reconciling Prometheus.
+ expr: rate(prometheus_operator_node_address_lookup_errors_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]) > 0.1
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusOperatorNotReady | default false) }}
+ - alert: PrometheusOperatorNotReady
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus operator in {{`{{`}} $labels.namespace {{`}}`}} namespace isn't ready to reconcile {{`{{`}} $labels.controller {{`}}`}} resources.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatornotready
+ summary: Prometheus operator not ready
+ expr: min by (controller,namespace) (max_over_time(prometheus_operator_ready{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]) == 0)
+ for: 5m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusOperatorRejectedResources | default false) }}
+ - alert: PrometheusOperatorRejectedResources
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus operator in {{`{{`}} $labels.namespace {{`}}`}} namespace rejected {{`{{`}} printf "%0.0f" $value {{`}}`}} {{`{{`}} $labels.controller {{`}}`}}/{{`{{`}} $labels.resource {{`}}`}} resources.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatorrejectedresources
+ summary: Resources rejected by Prometheus operator
+ expr: min_over_time(prometheus_operator_managed_resources{state="rejected",job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]) > 0
+ for: 5m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/rules-1.14/prometheus.yaml b/kube-prometheus-stack/templates/prometheus/rules-1.14/prometheus.yaml
new file mode 100644
index 00000000..358ca7a4
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/rules-1.14/prometheus.yaml
@@ -0,0 +1,448 @@
+{{- /*
+Generated from 'prometheus' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/prometheus-prometheusRule.yaml
+Do not change in-place! In order to change this file first read following link:
+https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack
+*/ -}}
+{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }}
+{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.prometheus }}
+{{- $prometheusJob := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "prometheus" }}
+{{- $namespace := printf "%s" (include "kube-prometheus-stack.namespace" .) }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+ name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "prometheus" | trunc 63 | trimSuffix "-" }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.defaultRules.labels }}
+{{ toYaml .Values.defaultRules.labels | indent 4 }}
+{{- end }}
+{{- if .Values.defaultRules.annotations }}
+ annotations:
+{{ toYaml .Values.defaultRules.annotations | indent 4 }}
+{{- end }}
+spec:
+ groups:
+ - name: prometheus
+ rules:
+{{- if not (.Values.defaultRules.disabled.PrometheusBadConfig | default false) }}
+ - alert: PrometheusBadConfig
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has failed to reload its configuration.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusbadconfig
+ summary: Failed Prometheus configuration reload.
+ expr: |-
+ # Without max_over_time, failed scrapes could create false negatives, see
+ # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details.
+ max_over_time(prometheus_config_last_reload_successful{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) == 0
+ for: 10m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusNotificationQueueRunningFull | default false) }}
+ - alert: PrometheusNotificationQueueRunningFull
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Alert notification queue of Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} is running full.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusnotificationqueuerunningfull
+ summary: Prometheus alert notification queue predicted to run full in less than 30m.
+ expr: |-
+ # Without min_over_time, failed scrapes could create false negatives, see
+ # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details.
+ (
+ predict_linear(prometheus_notifications_queue_length{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m], 60 * 30)
+ >
+ min_over_time(prometheus_notifications_queue_capacity{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m])
+ )
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusErrorSendingAlertsToSomeAlertmanagers | default false) }}
+ - alert: PrometheusErrorSendingAlertsToSomeAlertmanagers
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} printf "%.1f" $value {{`}}`}}% errors while sending alerts from Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} to Alertmanager {{`{{`}}$labels.alertmanager{{`}}`}}.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheuserrorsendingalertstosomealertmanagers
+ summary: Prometheus has encountered more than 1% errors sending alerts to a specific Alertmanager.
+ expr: |-
+ (
+ rate(prometheus_notifications_errors_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m])
+ /
+ rate(prometheus_notifications_sent_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m])
+ )
+ * 100
+ > 1
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusNotConnectedToAlertmanagers | default false) }}
+ - alert: PrometheusNotConnectedToAlertmanagers
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} is not connected to any Alertmanagers.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusnotconnectedtoalertmanagers
+ summary: Prometheus is not connected to any Alertmanagers.
+ expr: |-
+ # Without max_over_time, failed scrapes could create false negatives, see
+ # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details.
+ max_over_time(prometheus_notifications_alertmanagers_discovered{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) < 1
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusTSDBReloadsFailing | default false) }}
+ - alert: PrometheusTSDBReloadsFailing
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has detected {{`{{`}}$value | humanize{{`}}`}} reload failures over the last 3h.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheustsdbreloadsfailing
+ summary: Prometheus has issues reloading blocks from disk.
+ expr: increase(prometheus_tsdb_reloads_failures_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[3h]) > 0
+ for: 4h
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusTSDBCompactionsFailing | default false) }}
+ - alert: PrometheusTSDBCompactionsFailing
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has detected {{`{{`}}$value | humanize{{`}}`}} compaction failures over the last 3h.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheustsdbcompactionsfailing
+ summary: Prometheus has issues compacting blocks.
+ expr: increase(prometheus_tsdb_compactions_failed_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[3h]) > 0
+ for: 4h
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusNotIngestingSamples | default false) }}
+ - alert: PrometheusNotIngestingSamples
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} is not ingesting samples.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusnotingestingsamples
+ summary: Prometheus is not ingesting samples.
+ expr: |-
+ (
+ rate(prometheus_tsdb_head_samples_appended_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) <= 0
+ and
+ (
+ sum without(scrape_job) (prometheus_target_metadata_cache_entries{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}) > 0
+ or
+ sum without(rule_group) (prometheus_rule_group_rules{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}) > 0
+ )
+ )
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusDuplicateTimestamps | default false) }}
+ - alert: PrometheusDuplicateTimestamps
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} is dropping {{`{{`}} printf "%.4g" $value {{`}}`}} samples/s with different values but duplicated timestamp.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusduplicatetimestamps
+ summary: Prometheus is dropping samples with duplicate timestamps.
+ expr: rate(prometheus_target_scrapes_sample_duplicate_timestamp_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusOutOfOrderTimestamps | default false) }}
+ - alert: PrometheusOutOfOrderTimestamps
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} is dropping {{`{{`}} printf "%.4g" $value {{`}}`}} samples/s with timestamps arriving out of order.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusoutofordertimestamps
+ summary: Prometheus drops samples with out-of-order timestamps.
+ expr: rate(prometheus_target_scrapes_sample_out_of_order_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0
+ for: 10m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusRemoteStorageFailures | default false) }}
+ - alert: PrometheusRemoteStorageFailures
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} failed to send {{`{{`}} printf "%.1f" $value {{`}}`}}% of the samples to {{`{{`}} $labels.remote_name{{`}}`}}:{{`{{`}} $labels.url {{`}}`}}
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusremotestoragefailures
+ summary: Prometheus fails to send samples to remote storage.
+ expr: |-
+ (
+ (rate(prometheus_remote_storage_failed_samples_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) or rate(prometheus_remote_storage_samples_failed_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]))
+ /
+ (
+ (rate(prometheus_remote_storage_failed_samples_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) or rate(prometheus_remote_storage_samples_failed_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]))
+ +
+ (rate(prometheus_remote_storage_succeeded_samples_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) or rate(prometheus_remote_storage_samples_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]))
+ )
+ )
+ * 100
+ > 1
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusRemoteWriteBehind | default false) }}
+ - alert: PrometheusRemoteWriteBehind
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} remote write is {{`{{`}} printf "%.1f" $value {{`}}`}}s behind for {{`{{`}} $labels.remote_name{{`}}`}}:{{`{{`}} $labels.url {{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusremotewritebehind
+ summary: Prometheus remote write is behind.
+ expr: |-
+ # Without max_over_time, failed scrapes could create false negatives, see
+ # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details.
+ (
+ max_over_time(prometheus_remote_storage_highest_timestamp_in_seconds{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m])
+ - ignoring(remote_name, url) group_right
+ max_over_time(prometheus_remote_storage_queue_highest_sent_timestamp_seconds{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m])
+ )
+ > 120
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusRemoteWriteDesiredShards | default false) }}
+ - alert: PrometheusRemoteWriteDesiredShards
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} remote write desired shards calculation wants to run {{`{{`}} $value {{`}}`}} shards for queue {{`{{`}} $labels.remote_name{{`}}`}}:{{`{{`}} $labels.url {{`}}`}}, which is more than the max of {{`{{`}} printf `prometheus_remote_storage_shards_max{instance="%s",job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}` $labels.instance | query | first | value {{`}}`}}.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusremotewritedesiredshards
+ summary: Prometheus remote write desired shards calculation wants to run more than configured max shards.
+ expr: |-
+ # Without max_over_time, failed scrapes could create false negatives, see
+ # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details.
+ (
+ max_over_time(prometheus_remote_storage_shards_desired{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m])
+ >
+ max_over_time(prometheus_remote_storage_shards_max{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m])
+ )
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusRuleFailures | default false) }}
+ - alert: PrometheusRuleFailures
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has failed to evaluate {{`{{`}} printf "%.0f" $value {{`}}`}} rules in the last 5m.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusrulefailures
+ summary: Prometheus is failing rule evaluations.
+ expr: increase(prometheus_rule_evaluation_failures_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusMissingRuleEvaluations | default false) }}
+ - alert: PrometheusMissingRuleEvaluations
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has missed {{`{{`}} printf "%.0f" $value {{`}}`}} rule group evaluations in the last 5m.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusmissingruleevaluations
+ summary: Prometheus is missing rule evaluations due to slow rule group evaluation.
+ expr: increase(prometheus_rule_group_iterations_missed_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusTargetLimitHit | default false) }}
+ - alert: PrometheusTargetLimitHit
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has dropped {{`{{`}} printf "%.0f" $value {{`}}`}} targets because the number of targets exceeded the configured target_limit.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheustargetlimithit
+ summary: Prometheus has dropped targets because some scrape configs have exceeded the targets limit.
+ expr: increase(prometheus_target_scrape_pool_exceeded_target_limit_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusLabelLimitHit | default false) }}
+ - alert: PrometheusLabelLimitHit
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has dropped {{`{{`}} printf "%.0f" $value {{`}}`}} targets because some samples exceeded the configured label_limit, label_name_length_limit or label_value_length_limit.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheuslabellimithit
+ summary: Prometheus has dropped targets because some scrape configs have exceeded the labels limit.
+ expr: increase(prometheus_target_scrape_pool_exceeded_label_limits_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusScrapeBodySizeLimitHit | default false) }}
+ - alert: PrometheusScrapeBodySizeLimitHit
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has failed {{`{{`}} printf "%.0f" $value {{`}}`}} scrapes in the last 5m because some targets exceeded the configured body_size_limit.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusscrapebodysizelimithit
+ summary: Prometheus has dropped some targets that exceeded body size limit.
+ expr: increase(prometheus_target_scrapes_exceeded_body_size_limit_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusScrapeSampleLimitHit | default false) }}
+ - alert: PrometheusScrapeSampleLimitHit
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has failed {{`{{`}} printf "%.0f" $value {{`}}`}} scrapes in the last 5m because some targets exceeded the configured sample_limit.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusscrapesamplelimithit
+ summary: Prometheus has failed scrapes that have exceeded the configured sample limit.
+ expr: increase(prometheus_target_scrapes_exceeded_sample_limit_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusTargetSyncFailure | default false) }}
+ - alert: PrometheusTargetSyncFailure
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} printf "%.0f" $value {{`}}`}} targets in Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} have failed to sync because invalid configuration was supplied.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheustargetsyncfailure
+ summary: Prometheus has failed to sync targets.
+ expr: increase(prometheus_target_sync_failed_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[30m]) > 0
+ for: 5m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusHighQueryLoad | default false) }}
+ - alert: PrometheusHighQueryLoad
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} query API has less than 20% available capacity in its query engine for the last 15 minutes.
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheushighqueryload
+ summary: Prometheus is reaching its maximum capacity serving concurrent requests.
+ expr: avg_over_time(prometheus_engine_queries{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) / max_over_time(prometheus_engine_queries_concurrent_max{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0.8
+ for: 15m
+ labels:
+ severity: warning
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- if not (.Values.defaultRules.disabled.PrometheusErrorSendingAlertsToAnyAlertmanager | default false) }}
+ - alert: PrometheusErrorSendingAlertsToAnyAlertmanager
+ annotations:
+{{- if .Values.defaultRules.additionalRuleAnnotations }}
+{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }}
+{{- end }}
+ description: '{{`{{`}} printf "%.1f" $value {{`}}`}}% minimum errors while sending alerts from Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} to any Alertmanager.'
+ runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheuserrorsendingalertstoanyalertmanager
+ summary: Prometheus encounters more than 3% errors sending alerts to any Alertmanager.
+ expr: |-
+ min without (alertmanager) (
+ rate(prometheus_notifications_errors_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}",alertmanager!~``}[5m])
+ /
+ rate(prometheus_notifications_sent_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}",alertmanager!~``}[5m])
+ )
+ * 100
+ > 3
+ for: 15m
+ labels:
+ severity: critical
+{{- if .Values.defaultRules.additionalRuleLabels }}
+{{ toYaml .Values.defaultRules.additionalRuleLabels | indent 8 }}
+{{- end }}
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/kube-prometheus-stack/templates/prometheus/service.yaml b/kube-prometheus-stack/templates/prometheus/service.yaml
new file mode 100644
index 00000000..1e1f9c7b
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/service.yaml
@@ -0,0 +1,64 @@
+{{- if .Values.prometheus.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+ self-monitor: {{ .Values.prometheus.serviceMonitor.selfMonitor | quote }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.prometheus.service.labels }}
+{{ toYaml .Values.prometheus.service.labels | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.service.annotations }}
+ annotations:
+{{ toYaml .Values.prometheus.service.annotations | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.prometheus.service.clusterIP }}
+ clusterIP: {{ .Values.prometheus.service.clusterIP }}
+{{- end }}
+{{- if .Values.prometheus.service.externalIPs }}
+ externalIPs:
+{{ toYaml .Values.prometheus.service.externalIPs | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.service.loadBalancerIP }}
+ loadBalancerIP: {{ .Values.prometheus.service.loadBalancerIP }}
+{{- end }}
+{{- if .Values.prometheus.service.loadBalancerSourceRanges }}
+ loadBalancerSourceRanges:
+ {{- range $cidr := .Values.prometheus.service.loadBalancerSourceRanges }}
+ - {{ $cidr }}
+ {{- end }}
+{{- end }}
+{{- if ne .Values.prometheus.service.type "ClusterIP" }}
+ externalTrafficPolicy: {{ .Values.prometheus.service.externalTrafficPolicy }}
+{{- end }}
+ ports:
+ - name: {{ .Values.prometheus.prometheusSpec.portName }}
+ {{- if eq .Values.prometheus.service.type "NodePort" }}
+ nodePort: {{ .Values.prometheus.service.nodePort }}
+ {{- end }}
+ port: {{ .Values.prometheus.service.port }}
+ targetPort: {{ .Values.prometheus.service.targetPort }}
+ {{- if .Values.prometheus.thanosIngress.enabled }}
+ - name: grpc
+ {{- if eq .Values.prometheus.service.type "NodePort" }}
+ nodePort: {{ .Values.prometheus.thanosIngress.nodePort }}
+ {{- end }}
+ port: {{ .Values.prometheus.thanosIngress.servicePort }}
+ targetPort: {{ .Values.prometheus.thanosIngress.servicePort }}
+ {{- end }}
+{{- if .Values.prometheus.service.additionalPorts }}
+{{ toYaml .Values.prometheus.service.additionalPorts | indent 2 }}
+{{- end }}
+ publishNotReadyAddresses: {{ .Values.prometheus.service.publishNotReadyAddresses }}
+ selector:
+ app.kubernetes.io/name: prometheus
+ prometheus: {{ template "kube-prometheus-stack.prometheus.crname" . }}
+{{- if .Values.prometheus.service.sessionAffinity }}
+ sessionAffinity: {{ .Values.prometheus.service.sessionAffinity }}
+{{- end }}
+ type: "{{ .Values.prometheus.service.type }}"
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/serviceThanosSidecar.yaml b/kube-prometheus-stack/templates/prometheus/serviceThanosSidecar.yaml
new file mode 100644
index 00000000..2b80e774
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/serviceThanosSidecar.yaml
@@ -0,0 +1,39 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.thanosService.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-thanos-discovery
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-thanos-discovery
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.prometheus.thanosService.labels }}
+{{ toYaml .Values.prometheus.thanosService.labels | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.thanosService.annotations }}
+ annotations:
+{{ toYaml .Values.prometheus.thanosService.annotations | indent 4 }}
+{{- end }}
+spec:
+ type: {{ .Values.prometheus.thanosService.type }}
+ clusterIP: {{ .Values.prometheus.thanosService.clusterIP }}
+{{- if ne .Values.prometheus.thanosService.type "ClusterIP" }}
+ externalTrafficPolicy: {{ .Values.prometheus.thanosService.externalTrafficPolicy }}
+{{- end }}
+ ports:
+ - name: {{ .Values.prometheus.thanosService.portName }}
+ port: {{ .Values.prometheus.thanosService.port }}
+ targetPort: {{ .Values.prometheus.thanosService.targetPort }}
+ {{- if eq .Values.prometheus.thanosService.type "NodePort" }}
+ nodePort: {{ .Values.prometheus.thanosService.nodePort }}
+ {{- end }}
+ - name: {{ .Values.prometheus.thanosService.httpPortName }}
+ port: {{ .Values.prometheus.thanosService.httpPort }}
+ targetPort: {{ .Values.prometheus.thanosService.targetHttpPort }}
+ {{- if eq .Values.prometheus.thanosService.type "NodePort" }}
+ nodePort: {{ .Values.prometheus.thanosService.httpNodePort }}
+ {{- end }}
+ selector:
+ app.kubernetes.io/name: prometheus
+ prometheus: {{ template "kube-prometheus-stack.prometheus.crname" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/serviceThanosSidecarExternal.yaml b/kube-prometheus-stack/templates/prometheus/serviceThanosSidecarExternal.yaml
new file mode 100644
index 00000000..fa45934d
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/serviceThanosSidecarExternal.yaml
@@ -0,0 +1,46 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.thanosServiceExternal.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-thanos-external
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.prometheus.thanosServiceExternal.labels }}
+{{ toYaml .Values.prometheus.thanosServiceExternal.labels | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.thanosServiceExternal.annotations }}
+ annotations:
+{{ toYaml .Values.prometheus.thanosServiceExternal.annotations | indent 4 }}
+{{- end }}
+spec:
+ type: {{ .Values.prometheus.thanosServiceExternal.type }}
+{{- if .Values.prometheus.thanosServiceExternal.loadBalancerIP }}
+ loadBalancerIP: {{ .Values.prometheus.thanosServiceExternal.loadBalancerIP }}
+{{- end }}
+{{- if .Values.prometheus.thanosServiceExternal.loadBalancerSourceRanges }}
+ loadBalancerSourceRanges:
+ {{- range $cidr := .Values.prometheus.thanosServiceExternal.loadBalancerSourceRanges }}
+ - {{ $cidr }}
+ {{- end }}
+{{- end }}
+{{- if ne .Values.prometheus.thanosServiceExternal.type "ClusterIP" }}
+ externalTrafficPolicy: {{ .Values.prometheus.thanosServiceExternal.externalTrafficPolicy }}
+{{- end }}
+ ports:
+ - name: {{ .Values.prometheus.thanosServiceExternal.portName }}
+ port: {{ .Values.prometheus.thanosServiceExternal.port }}
+ targetPort: {{ .Values.prometheus.thanosServiceExternal.targetPort }}
+ {{- if eq .Values.prometheus.thanosServiceExternal.type "NodePort" }}
+ nodePort: {{ .Values.prometheus.thanosServiceExternal.nodePort }}
+ {{- end }}
+ - name: {{ .Values.prometheus.thanosServiceExternal.httpPortName }}
+ port: {{ .Values.prometheus.thanosServiceExternal.httpPort }}
+ targetPort: {{ .Values.prometheus.thanosServiceExternal.targetHttpPort }}
+ {{- if eq .Values.prometheus.thanosServiceExternal.type "NodePort" }}
+ nodePort: {{ .Values.prometheus.thanosServiceExternal.httpNodePort }}
+ {{- end }}
+ selector:
+ app.kubernetes.io/name: prometheus
+ prometheus: {{ template "kube-prometheus-stack.prometheus.crname" . }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/serviceaccount.yaml b/kube-prometheus-stack/templates/prometheus/serviceaccount.yaml
new file mode 100644
index 00000000..dde1632d
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/serviceaccount.yaml
@@ -0,0 +1,20 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.serviceAccount.create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ template "kube-prometheus-stack.prometheus.serviceAccountName" . }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+ app.kubernetes.io/name: {{ template "kube-prometheus-stack.name" . }}-prometheus
+ app.kubernetes.io/component: prometheus
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.prometheus.serviceAccount.annotations }}
+ annotations:
+{{ toYaml .Values.prometheus.serviceAccount.annotations | indent 4 }}
+{{- end }}
+{{- if .Values.global.imagePullSecrets }}
+imagePullSecrets:
+{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 2 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/servicemonitor.yaml b/kube-prometheus-stack/templates/prometheus/servicemonitor.yaml
new file mode 100644
index 00000000..356c013f
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/servicemonitor.yaml
@@ -0,0 +1,42 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.serviceMonitor.selfMonitor }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ selector:
+ matchLabels:
+ app: {{ template "kube-prometheus-stack.name" . }}-prometheus
+ release: {{ $.Release.Name | quote }}
+ self-monitor: "true"
+ namespaceSelector:
+ matchNames:
+ - {{ printf "%s" (include "kube-prometheus-stack.namespace" .) | quote }}
+ endpoints:
+ - port: {{ .Values.prometheus.prometheusSpec.portName }}
+ {{- if .Values.prometheus.serviceMonitor.interval }}
+ interval: {{ .Values.prometheus.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.prometheus.serviceMonitor.scheme }}
+ scheme: {{ .Values.prometheus.serviceMonitor.scheme }}
+ {{- end }}
+ {{- if .Values.prometheus.serviceMonitor.tlsConfig }}
+ tlsConfig: {{ toYaml .Values.prometheus.serviceMonitor.tlsConfig | nindent 6 }}
+ {{- end }}
+ {{- if .Values.prometheus.serviceMonitor.bearerTokenFile }}
+ bearerTokenFile: {{ .Values.prometheus.serviceMonitor.bearerTokenFile }}
+ {{- end }}
+ path: "{{ trimSuffix "/" .Values.prometheus.prometheusSpec.routePrefix }}/metrics"
+{{- if .Values.prometheus.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.prometheus.serviceMonitor.metricRelabelings | indent 6) . }}
+{{- end }}
+{{- if .Values.prometheus.serviceMonitor.relabelings }}
+ relabelings:
+{{ toYaml .Values.prometheus.serviceMonitor.relabelings | indent 6 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/servicemonitorThanosSidecar.yaml b/kube-prometheus-stack/templates/prometheus/servicemonitorThanosSidecar.yaml
new file mode 100644
index 00000000..f2644d98
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/servicemonitorThanosSidecar.yaml
@@ -0,0 +1,41 @@
+{{- if and .Values.prometheus.thanosService.enabled .Values.prometheus.thanosServiceMonitor.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-thanos-sidecar
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-thanos-sidecar
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ selector:
+ matchLabels:
+ app: {{ template "kube-prometheus-stack.name" . }}-thanos-discovery
+ release: {{ $.Release.Name | quote }}
+ namespaceSelector:
+ matchNames:
+ - {{ printf "%s" (include "kube-prometheus-stack.namespace" .) | quote }}
+ endpoints:
+ - port: {{ .Values.prometheus.thanosService.httpPortName }}
+ {{- if .Values.prometheus.thanosServiceMonitor.interval }}
+ interval: {{ .Values.prometheus.thanosServiceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.prometheus.thanosServiceMonitor.scheme }}
+ scheme: {{ .Values.prometheus.thanosServiceMonitor.scheme }}
+ {{- end }}
+ {{- if .Values.prometheus.thanosServiceMonitor.tlsConfig }}
+ tlsConfig: {{ toYaml .Values.prometheus.thanosServiceMonitor.tlsConfig | nindent 6 }}
+ {{- end }}
+ {{- if .Values.prometheus.thanosServiceMonitor.bearerTokenFile }}
+ bearerTokenFile: {{ .Values.prometheus.thanosServiceMonitor.bearerTokenFile }}
+ {{- end }}
+ path: "/metrics"
+{{- if .Values.prometheus.thanosServiceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.prometheus.thanosServiceMonitor.metricRelabelings | indent 6) . }}
+{{- end }}
+{{- if .Values.prometheus.thanosServiceMonitor.relabelings }}
+ relabelings:
+{{ toYaml .Values.prometheus.thanosServiceMonitor.relabelings | indent 6 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/servicemonitors.yaml b/kube-prometheus-stack/templates/prometheus/servicemonitors.yaml
new file mode 100644
index 00000000..a78d1cd0
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/servicemonitors.yaml
@@ -0,0 +1,38 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.additionalServiceMonitors }}
+apiVersion: v1
+kind: List
+items:
+{{- range .Values.prometheus.additionalServiceMonitors }}
+ - apiVersion: monitoring.coreos.com/v1
+ kind: ServiceMonitor
+ metadata:
+ name: {{ .name }}
+ namespace: {{ template "kube-prometheus-stack.namespace" $ }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" $ }}-prometheus
+{{ include "kube-prometheus-stack.labels" $ | indent 8 }}
+ {{- if .additionalLabels }}
+{{ toYaml .additionalLabels | indent 8 }}
+ {{- end }}
+ spec:
+ endpoints:
+{{ toYaml .endpoints | indent 8 }}
+ {{- if .jobLabel }}
+ jobLabel: {{ .jobLabel }}
+ {{- end }}
+ {{- if .namespaceSelector }}
+ namespaceSelector:
+{{ toYaml .namespaceSelector | indent 8 }}
+ {{- end }}
+ selector:
+{{ toYaml .selector | indent 8 }}
+ {{- if .targetLabels }}
+ targetLabels:
+{{ toYaml .targetLabels | indent 8 }}
+ {{- end }}
+ {{- if .podTargetLabels }}
+ podTargetLabels:
+{{ toYaml .podTargetLabels | indent 8 }}
+ {{- end }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/prometheus/serviceperreplica.yaml b/kube-prometheus-stack/templates/prometheus/serviceperreplica.yaml
new file mode 100644
index 00000000..8d2fdc33
--- /dev/null
+++ b/kube-prometheus-stack/templates/prometheus/serviceperreplica.yaml
@@ -0,0 +1,49 @@
+{{- if and .Values.prometheus.enabled .Values.prometheus.servicePerReplica.enabled }}
+{{- $count := .Values.prometheus.prometheusSpec.replicas | int -}}
+{{- $serviceValues := .Values.prometheus.servicePerReplica -}}
+apiVersion: v1
+kind: List
+metadata:
+ name: {{ include "kube-prometheus-stack.fullname" $ }}-prometheus-serviceperreplica
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+items:
+{{- range $i, $e := until $count }}
+ - apiVersion: v1
+ kind: Service
+ metadata:
+ name: {{ include "kube-prometheus-stack.fullname" $ }}-prometheus-{{ $i }}
+ namespace: {{ template "kube-prometheus-stack.namespace" $ }}
+ labels:
+ app: {{ include "kube-prometheus-stack.name" $ }}-prometheus
+{{ include "kube-prometheus-stack.labels" $ | indent 8 }}
+ {{- if $serviceValues.annotations }}
+ annotations:
+{{ toYaml $serviceValues.annotations | indent 8 }}
+ {{- end }}
+ spec:
+ {{- if $serviceValues.clusterIP }}
+ clusterIP: {{ $serviceValues.clusterIP }}
+ {{- end }}
+ {{- if $serviceValues.loadBalancerSourceRanges }}
+ loadBalancerSourceRanges:
+ {{- range $cidr := $serviceValues.loadBalancerSourceRanges }}
+ - {{ $cidr }}
+ {{- end }}
+ {{- end }}
+ {{- if ne $serviceValues.type "ClusterIP" }}
+ externalTrafficPolicy: {{ $serviceValues.externalTrafficPolicy }}
+ {{- end }}
+ ports:
+ - name: {{ $.Values.prometheus.prometheusSpec.portName }}
+ {{- if eq $serviceValues.type "NodePort" }}
+ nodePort: {{ $serviceValues.nodePort }}
+ {{- end }}
+ port: {{ $serviceValues.port }}
+ targetPort: {{ $serviceValues.targetPort }}
+ selector:
+ app.kubernetes.io/name: prometheus
+ prometheus: {{ include "kube-prometheus-stack.prometheus.crname" $ }}
+ statefulset.kubernetes.io/pod-name: prometheus-{{ include "kube-prometheus-stack.prometheus.crname" $ }}-{{ $i }}
+ type: "{{ $serviceValues.type }}"
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/thanos-ruler/extrasecret.yaml b/kube-prometheus-stack/templates/thanos-ruler/extrasecret.yaml
new file mode 100644
index 00000000..fe2ea5be
--- /dev/null
+++ b/kube-prometheus-stack/templates/thanos-ruler/extrasecret.yaml
@@ -0,0 +1,20 @@
+{{- if .Values.thanosRuler.extraSecret.data -}}
+{{- $secretName := printf "thanos-ruler-%s-extra" (include "kube-prometheus-stack.fullname" . ) -}}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ default $secretName .Values.thanosRuler.extraSecret.name }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- if .Values.thanosRuler.extraSecret.annotations }}
+ annotations:
+{{ toYaml .Values.thanosRuler.extraSecret.annotations | indent 4 }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-thanos-ruler
+ app.kubernetes.io/component: thanos-ruler
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+data:
+{{- range $key, $val := .Values.thanosRuler.extraSecret.data }}
+ {{ $key }}: {{ $val | b64enc | quote }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/thanos-ruler/ingress.yaml b/kube-prometheus-stack/templates/thanos-ruler/ingress.yaml
new file mode 100644
index 00000000..2760805c
--- /dev/null
+++ b/kube-prometheus-stack/templates/thanos-ruler/ingress.yaml
@@ -0,0 +1,77 @@
+{{- if and .Values.thanosRuler.enabled .Values.thanosRuler.ingress.enabled }}
+{{- $pathType := .Values.thanosRuler.ingress.pathType | default "ImplementationSpecific" }}
+{{- $serviceName := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "thanos-ruler" }}
+{{- $servicePort := .Values.thanosRuler.service.port -}}
+{{- $routePrefix := list .Values.thanosRuler.thanosRulerSpec.routePrefix }}
+{{- $paths := .Values.thanosRuler.ingress.paths | default $routePrefix -}}
+{{- $apiIsStable := eq (include "kube-prometheus-stack.ingress.isStable" .) "true" -}}
+{{- $ingressSupportsPathType := eq (include "kube-prometheus-stack.ingress.supportsPathType" .) "true" -}}
+apiVersion: {{ include "kube-prometheus-stack.ingress.apiVersion" . }}
+kind: Ingress
+metadata:
+ name: {{ $serviceName }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+{{- if .Values.thanosRuler.ingress.annotations }}
+ annotations:
+{{ toYaml .Values.thanosRuler.ingress.annotations | indent 4 }}
+{{- end }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-thanos-ruler
+{{- if .Values.thanosRuler.ingress.labels }}
+{{ toYaml .Values.thanosRuler.ingress.labels | indent 4 }}
+{{- end }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ {{- if $apiIsStable }}
+ {{- if .Values.thanosRuler.ingress.ingressClassName }}
+ ingressClassName: {{ .Values.thanosRuler.ingress.ingressClassName }}
+ {{- end }}
+ {{- end }}
+ rules:
+ {{- if .Values.thanosRuler.ingress.hosts }}
+ {{- range $host := .Values.thanosRuler.ingress.hosts }}
+ - host: {{ tpl $host $ }}
+ http:
+ paths:
+ {{- range $p := $paths }}
+ - path: {{ tpl $p $ }}
+ {{- if and $pathType $ingressSupportsPathType }}
+ pathType: {{ $pathType }}
+ {{- end }}
+ backend:
+ {{- if $apiIsStable }}
+ service:
+ name: {{ $serviceName }}
+ port:
+ number: {{ $servicePort }}
+ {{- else }}
+ serviceName: {{ $serviceName }}
+ servicePort: {{ $servicePort }}
+ {{- end }}
+ {{- end -}}
+ {{- end -}}
+ {{- else }}
+ - http:
+ paths:
+ {{- range $p := $paths }}
+ - path: {{ tpl $p $ }}
+ {{- if and $pathType $ingressSupportsPathType }}
+ pathType: {{ $pathType }}
+ {{- end }}
+ backend:
+ {{- if $apiIsStable }}
+ service:
+ name: {{ $serviceName }}
+ port:
+ number: {{ $servicePort }}
+ {{- else }}
+ serviceName: {{ $serviceName }}
+ servicePort: {{ $servicePort }}
+ {{- end }}
+ {{- end -}}
+ {{- end -}}
+ {{- if .Values.thanosRuler.ingress.tls }}
+ tls:
+{{ tpl (toYaml .Values.thanosRuler.ingress.tls | indent 4) . }}
+ {{- end -}}
+{{- end -}}
diff --git a/kube-prometheus-stack/templates/thanos-ruler/podDisruptionBudget.yaml b/kube-prometheus-stack/templates/thanos-ruler/podDisruptionBudget.yaml
new file mode 100644
index 00000000..d3d378d6
--- /dev/null
+++ b/kube-prometheus-stack/templates/thanos-ruler/podDisruptionBudget.yaml
@@ -0,0 +1,21 @@
+{{- if and .Values.thanosRuler.enabled .Values.thanosRuler.podDisruptionBudget.enabled }}
+apiVersion: {{ include "kube-prometheus-stack.pdb.apiVersion" . }}
+kind: PodDisruptionBudget
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-thanos-ruler
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-thanos-ruler
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ {{- if .Values.thanosRuler.podDisruptionBudget.minAvailable }}
+ minAvailable: {{ .Values.thanosRuler.podDisruptionBudget.minAvailable }}
+ {{- end }}
+ {{- if .Values.thanosRuler.podDisruptionBudget.maxUnavailable }}
+ maxUnavailable: {{ .Values.thanosRuler.podDisruptionBudget.maxUnavailable }}
+ {{- end }}
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: thanos-ruler
+ thanos-ruler: {{ template "kube-prometheus-stack.fullname" . }}-thanos-ruler
+{{- end }}
diff --git a/kube-prometheus-stack/templates/thanos-ruler/ruler.yaml b/kube-prometheus-stack/templates/thanos-ruler/ruler.yaml
new file mode 100644
index 00000000..1f294f8d
--- /dev/null
+++ b/kube-prometheus-stack/templates/thanos-ruler/ruler.yaml
@@ -0,0 +1,168 @@
+{{- if .Values.thanosRuler.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ThanosRuler
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-thanos-ruler
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-thanos-ruler
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.thanosRuler.annotations }}
+ annotations:
+{{ toYaml .Values.thanosRuler.annotations | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.thanosRuler.thanosRulerSpec.image }}
+ {{- if and .Values.thanosRuler.thanosRulerSpec.image.tag .Values.thanosRuler.thanosRulerSpec.image.sha }}
+ image: "{{ .Values.thanosRuler.thanosRulerSpec.image.repository }}:{{ .Values.thanosRuler.thanosRulerSpec.image.tag }}@sha256:{{ .Values.thanosRuler.thanosRulerSpec.image.sha }}"
+ {{- else if .Values.thanosRuler.thanosRulerSpec.image.sha }}
+ image: "{{ .Values.thanosRuler.thanosRulerSpec.image.repository }}@sha256:{{ .Values.thanosRuler.thanosRulerSpec.image.sha }}"
+ {{- else if .Values.thanosRuler.thanosRulerSpec.image.tag }}
+ image: "{{ .Values.thanosRuler.thanosRulerSpec.image.repository }}:{{ .Values.thanosRuler.thanosRulerSpec.image.tag }}"
+ {{- else }}
+ image: "{{ .Values.thanosRuler.thanosRulerSpec.image.repository }}"
+ {{- end }}
+ {{- if .Values.thanosRuler.thanosRulerSpec.image.sha }}
+ sha: {{ .Values.thanosRuler.thanosRulerSpec.image.sha }}
+ {{- end }}
+{{- end }}
+ replicas: {{ .Values.thanosRuler.thanosRulerSpec.replicas }}
+ listenLocal: {{ .Values.thanosRuler.thanosRulerSpec.listenLocal }}
+ serviceAccountName: {{ template "kube-prometheus-stack.thanosRuler.serviceAccountName" . }}
+{{- if .Values.thanosRuler.thanosRulerSpec.externalPrefix }}
+ externalPrefix: "{{ tpl .Values.thanosRuler.thanosRulerSpec.externalPrefix . }}"
+{{- else if and .Values.thanosRuler.ingress.enabled .Values.thanosRuler.ingress.hosts }}
+ externalPrefix: "http://{{ tpl (index .Values.thanosRuler.ingress.hosts 0) . }}{{ .Values.thanosRuler.thanosRulerSpec.routePrefix }}"
+{{- else }}
+ externalPrefix: http://{{ template "kube-prometheus-stack.fullname" . }}-thanosRuler.{{ template "kube-prometheus-stack.namespace" . }}:{{ .Values.thanosRuler.service.port }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.nodeSelector }}
+ nodeSelector:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.nodeSelector | indent 4 }}
+{{- end }}
+ paused: {{ .Values.thanosRuler.thanosRulerSpec.paused }}
+ logFormat: {{ .Values.thanosRuler.thanosRulerSpec.logFormat | quote }}
+ logLevel: {{ .Values.thanosRuler.thanosRulerSpec.logLevel | quote }}
+ retention: {{ .Values.thanosRuler.thanosRulerSpec.retention | quote }}
+{{- if .Values.thanosRuler.thanosRulerSpec.evaluationInterval }}
+ evaluationInterval: {{ .Values.thanosRuler.thanosRulerSpec.evaluationInterval }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.ruleNamespaceSelector }}
+ ruleNamespaceSelector:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.ruleNamespaceSelector | indent 4 }}
+{{ else }}
+ ruleNamespaceSelector: {}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.ruleSelector }}
+ ruleSelector:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.ruleSelector | indent 4}}
+{{- else if .Values.thanosRuler.thanosRulerSpec.ruleSelectorNilUsesHelmValues }}
+ ruleSelector:
+ matchLabels:
+ release: {{ $.Release.Name | quote }}
+{{ else }}
+ ruleSelector: {}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.alertQueryUrl }}
+ alertQueryUrl: "{{ .Values.thanosRuler.thanosRulerSpec.alertQueryUrl }}"
+{{- end}}
+{{- if .Values.thanosRuler.thanosRulerSpec.alertmanagersUrl }}
+ alertmanagersUrl:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.alertmanagersUrl | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.alertmanagersConfig }}
+ alertmanagersConfig:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.alertmanagersConfig | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.queryEndpoints }}
+ queryEndpoints:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.queryEndpoints | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.resources }}
+ resources:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.resources | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.routePrefix }}
+ routePrefix: "{{ .Values.thanosRuler.thanosRulerSpec.routePrefix }}"
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.securityContext }}
+ securityContext:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.securityContext | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.storage }}
+ storage:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.storage | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.objectStorageConfig }}
+ objectStorageConfig:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.objectStorageConfig | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.labels }}
+ labels:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.labels | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.objectStorageConfigFile }}
+ objectStorageConfigFile: {{ .Values.thanosRuler.thanosRulerSpec.objectStorageConfigFile }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.podMetadata }}
+ podMetadata:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.podMetadata | indent 4 }}
+{{- end }}
+{{- if or .Values.thanosRuler.thanosRulerSpec.podAntiAffinity .Values.thanosRuler.thanosRulerSpec.affinity }}
+ affinity:
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.affinity }}
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.affinity | indent 4 }}
+{{- end }}
+{{- if eq .Values.thanosRuler.thanosRulerSpec.podAntiAffinity "hard" }}
+ podAntiAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ - topologyKey: {{ .Values.thanosRuler.thanosRulerSpec.podAntiAffinityTopologyKey }}
+ labelSelector:
+ matchExpressions:
+ - {key: app.kubernetes.io/name, operator: In, values: [thanos-ruler]}
+ - {key: thanos-ruler, operator: In, values: [{{ template "kube-prometheus-stack.fullname" . }}-thanos-ruler]}
+{{- else if eq .Values.thanosRuler.thanosRulerSpec.podAntiAffinity "soft" }}
+ podAntiAffinity:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ - weight: 100
+ podAffinityTerm:
+ topologyKey: {{ .Values.thanosRuler.thanosRulerSpec.podAntiAffinityTopologyKey }}
+ labelSelector:
+ matchExpressions:
+ - {key: app.kubernetes.io/name, operator: In, values: [thanos-ruler]}
+ - {key: thanos-ruler, operator: In, values: [{{ template "kube-prometheus-stack.fullname" . }}-thanos-ruler]}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.tolerations }}
+ tolerations:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.tolerations | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.topologySpreadConstraints }}
+ topologySpreadConstraints:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.topologySpreadConstraints | indent 4 }}
+{{- end }}
+{{- if .Values.global.imagePullSecrets }}
+ imagePullSecrets:
+{{ toYaml .Values.global.imagePullSecrets | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.containers }}
+ containers:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.containers | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.initContainers }}
+ initContainers:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.initContainers | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.priorityClassName }}
+ priorityClassName: {{.Values.thanosRuler.thanosRulerSpec.priorityClassName }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.volumes }}
+ volumes:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.volumes | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.thanosRulerSpec.volumeMounts }}
+ volumeMounts:
+{{ toYaml .Values.thanosRuler.thanosRulerSpec.volumeMounts | indent 4 }}
+{{- end }}
+ portName: {{ .Values.thanosRuler.thanosRulerSpec.portName }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/thanos-ruler/service.yaml b/kube-prometheus-stack/templates/thanos-ruler/service.yaml
new file mode 100644
index 00000000..093dbf7c
--- /dev/null
+++ b/kube-prometheus-stack/templates/thanos-ruler/service.yaml
@@ -0,0 +1,53 @@
+{{- if .Values.thanosRuler.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-thanos-ruler
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-thanos-ruler
+ self-monitor: {{ .Values.thanosRuler.serviceMonitor.selfMonitor | quote }}
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.thanosRuler.service.labels }}
+{{ toYaml .Values.thanosRuler.service.labels | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.service.annotations }}
+ annotations:
+{{ toYaml .Values.thanosRuler.service.annotations | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.thanosRuler.service.clusterIP }}
+ clusterIP: {{ .Values.thanosRuler.service.clusterIP }}
+{{- end }}
+{{- if .Values.thanosRuler.service.externalIPs }}
+ externalIPs:
+{{ toYaml .Values.thanosRuler.service.externalIPs | indent 4 }}
+{{- end }}
+{{- if .Values.thanosRuler.service.loadBalancerIP }}
+ loadBalancerIP: {{ .Values.thanosRuler.service.loadBalancerIP }}
+{{- end }}
+{{- if .Values.thanosRuler.service.loadBalancerSourceRanges }}
+ loadBalancerSourceRanges:
+ {{- range $cidr := .Values.thanosRuler.service.loadBalancerSourceRanges }}
+ - {{ $cidr }}
+ {{- end }}
+{{- end }}
+{{- if ne .Values.thanosRuler.service.type "ClusterIP" }}
+ externalTrafficPolicy: {{ .Values.thanosRuler.service.externalTrafficPolicy }}
+{{- end }}
+ ports:
+ - name: {{ .Values.thanosRuler.thanosRulerSpec.portName }}
+ {{- if eq .Values.thanosRuler.service.type "NodePort" }}
+ nodePort: {{ .Values.thanosRuler.service.nodePort }}
+ {{- end }}
+ port: {{ .Values.thanosRuler.service.port }}
+ targetPort: {{ .Values.thanosRuler.service.targetPort }}
+ protocol: TCP
+{{- if .Values.thanosRuler.service.additionalPorts }}
+{{ toYaml .Values.thanosRuler.service.additionalPorts | indent 2 }}
+{{- end }}
+ selector:
+ app.kubernetes.io/name: thanos-ruler
+ thanos-ruler: {{ template "kube-prometheus-stack.fullname" . }}-thanos-ruler
+ type: "{{ .Values.thanosRuler.service.type }}"
+{{- end }}
diff --git a/kube-prometheus-stack/templates/thanos-ruler/serviceaccount.yaml b/kube-prometheus-stack/templates/thanos-ruler/serviceaccount.yaml
new file mode 100644
index 00000000..0138c357
--- /dev/null
+++ b/kube-prometheus-stack/templates/thanos-ruler/serviceaccount.yaml
@@ -0,0 +1,20 @@
+{{- if and .Values.thanosRuler.enabled .Values.thanosRuler.serviceAccount.create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ template "kube-prometheus-stack.thanosRuler.serviceAccountName" . }}
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-thanos-ruler
+ app.kubernetes.io/name: {{ template "kube-prometheus-stack.name" . }}-thanos-ruler
+ app.kubernetes.io/component: thanos-ruler
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+{{- if .Values.thanosRuler.serviceAccount.annotations }}
+ annotations:
+{{ toYaml .Values.thanosRuler.serviceAccount.annotations | indent 4 }}
+{{- end }}
+{{- if .Values.global.imagePullSecrets }}
+imagePullSecrets:
+{{ toYaml .Values.global.imagePullSecrets | indent 2 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/templates/thanos-ruler/servicemonitor.yaml b/kube-prometheus-stack/templates/thanos-ruler/servicemonitor.yaml
new file mode 100644
index 00000000..4a05679b
--- /dev/null
+++ b/kube-prometheus-stack/templates/thanos-ruler/servicemonitor.yaml
@@ -0,0 +1,45 @@
+{{- if and .Values.thanosRuler.enabled .Values.thanosRuler.serviceMonitor.selfMonitor }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ template "kube-prometheus-stack.fullname" . }}-thanos-ruler
+ namespace: {{ template "kube-prometheus-stack.namespace" . }}
+ labels:
+ app: {{ template "kube-prometheus-stack.name" . }}-thanos-ruler
+{{ include "kube-prometheus-stack.labels" . | indent 4 }}
+spec:
+ selector:
+ matchLabels:
+ app: {{ template "kube-prometheus-stack.name" . }}-thanos-ruler
+ release: {{ $.Release.Name | quote }}
+ self-monitor: {{ .Values.thanosRuler.serviceMonitor.selfMonitor | quote }}
+ namespaceSelector:
+ matchNames:
+ - {{ printf "%s" (include "kube-prometheus-stack.namespace" .) | quote }}
+ endpoints:
+ - port: {{ .Values.thanosRuler.thanosRulerSpec.portName }}
+ {{- if .Values.thanosRuler.serviceMonitor.interval }}
+ interval: {{ .Values.thanosRuler.serviceMonitor.interval }}
+ {{- end }}
+ {{- if .Values.thanosRuler.serviceMonitor.proxyUrl }}
+ proxyUrl: {{ .Values.thanosRuler.serviceMonitor.proxyUrl}}
+ {{- end }}
+ {{- if .Values.thanosRuler.serviceMonitor.scheme }}
+ scheme: {{ .Values.thanosRuler.serviceMonitor.scheme }}
+ {{- end }}
+ {{- if .Values.thanosRuler.serviceMonitor.bearerTokenFile }}
+ bearerTokenFile: {{ .Values.thanosRuler.serviceMonitor.bearerTokenFile }}
+ {{- end }}
+ {{- if .Values.thanosRuler.serviceMonitor.tlsConfig }}
+ tlsConfig: {{ toYaml .Values.thanosRuler.serviceMonitor.tlsConfig | nindent 6 }}
+ {{- end }}
+ path: "{{ trimSuffix "/" .Values.thanosRuler.thanosRulerSpec.routePrefix }}/metrics"
+{{- if .Values.thanosRuler.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+{{ tpl (toYaml .Values.thanosRuler.serviceMonitor.metricRelabelings | indent 6) . }}
+{{- end }}
+{{- if .Values.thanosRuler.serviceMonitor.relabelings }}
+ relabelings:
+{{ toYaml .Values.thanosRuler.serviceMonitor.relabelings | indent 6 }}
+{{- end }}
+{{- end }}
diff --git a/kube-prometheus-stack/values.yaml b/kube-prometheus-stack/values.yaml
new file mode 100644
index 00000000..627c7e85
--- /dev/null
+++ b/kube-prometheus-stack/values.yaml
@@ -0,0 +1,177 @@
+
+fullnameOverride: prometheus #deployment_name
+
+defaultRules:
+ create: true
+ rules:
+ alertmanager: true
+ etcd: true
+ configReloaders: true
+ general: true
+ k8s: true
+ kubeApiserverAvailability: true
+ kubeApiserverBurnrate: true
+ kubeApiserverHistogram: true
+ kubeApiserverSlos: true
+ kubelet: true
+ kubeProxy: true
+ kubePrometheusGeneral: true
+ kubePrometheusNodeRecording: true
+ kubernetesApps: true
+ kubernetesResources: true
+ kubernetesStorage: true
+ kubernetesSystem: true
+ kubeScheduler: true
+ kubeStateMetrics: true
+ network: true
+ node: true
+ nodeExporterAlerting: true
+ nodeExporterRecording: true
+ prometheus: true
+ prometheusOperator: true
+
+alertmanager:
+ fullnameOverride: alertmanager
+ enabled: true
+ ingress:
+ enabled: false
+
+serviceAccount:
+ create: false
+
+grafana:
+ enabled: true
+ fullnameOverride: grafana
+ forceDeployDatasources: false
+ forceDeployDashboards: false
+ defaultDashboardsEnabled: true
+ defaultDashboardsTimezone: utc
+ serviceMonitor:
+ enabled: true
+ admin:
+ existingSecret: grafana-admin-credentials #For secure password, we will create a secret named `grafana-admin-credentials` and store it in kubernetes and use that secret for grafana.
+ userKey: admin-user
+ passwordKey: admin-password
+
+kubeApiServer:
+ enabled: true
+
+kubelet:
+ enabled: true
+ serviceMonitor:
+ metricRelabelings:
+ - action: replace
+ sourceLabels:
+ - node
+ targetLabel: instance
+
+kubeControllerManager:
+ enabled: true
+ endpoints: [] # ips of servers
+
+
+coreDns:
+ enabled: true
+
+kubeDns:
+ enabled: false
+
+kubeEtcd:
+ enabled: true
+ endpoints: [] # ips of servers
+
+ service:
+ enabled: true
+ port: 2381
+ targetPort: 2381
+
+kubeScheduler:
+ enabled: true
+ endpoints: [] # ips of servers
+
+
+kubeProxy:
+ enabled: true
+ endpoints: [] # ips of servers
+
+
+kubeStateMetrics:
+ enabled: true
+
+kube-state-metrics:
+ fullnameOverride: kube-state-metrics
+ selfMonitor:
+ enabled: true
+ prometheus:
+ monitor:
+ enabled: true
+ relabelings: #we are replacing the node's ip addresses with the node names
+ - action: replace
+ regex: (.*)
+ replacement: $1
+ sourceLabels:
+ - __meta_kubernetes_pod_node_name
+ targetLabel: kubernetes_node
+
+nodeExporter:
+ enabled: true
+ serviceMonitor:
+ relabelings:
+ - action: replace
+ regex: (.*)
+ replacement: $1
+ sourceLabels:
+ - __meta_kubernetes_pod_node_name
+ targetLabel: kubernetes_node
+
+prometheus-node-exporter:
+ fullnameOverride: node-exporter
+ podLabels:
+ jobLabel: node-exporter
+ extraArgs:
+ - --collector.filesystem.mount-points-exclude=^/(dev|proc|sys|var/lib/docker/.+|var/lib/kubelet/.+)($|/)
+ - --collector.filesystem.fs-types-exclude=^(autofs|binfmt_misc|bpf|cgroup2?|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|iso9660|mqueue|nsfs|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|selinuxfs|squashfs|sysfs|tracefs)$
+ service:
+ portName: http-metrics
+ prometheus:
+ monitor:
+ enabled: true
+ relabelings:
+ - action: replace
+ regex: (.*)
+ replacement: $1
+ sourceLabels:
+ - __meta_kubernetes_pod_node_name
+ targetLabel: kubernetes_node
+ resources:
+ requests:
+ memory: 512Mi
+ cpu: 250m
+ limits:
+ memory: 2048Mi
+
+prometheusOperator:
+ enabled: true
+ prometheusConfigReloader:
+ resources:
+ requests:
+ cpu: 200m
+ memory: 50Mi
+ limits:
+ memory: 100Mi
+
+prometheus:
+ enabled: true
+ prometheusSpec:
+ replicas: 1
+ replicaExternalLabelName: "replica"
+ ruleSelectorNilUsesHelmValues: false
+ serviceMonitorSelectorNilUsesHelmValues: false
+ podMonitorSelectorNilUsesHelmValues: false
+ probeSelectorNilUsesHelmValues: false
+ retention: 6h
+ enableAdminAPI: true
+ walCompression: true
+
+thanosRuler:
+ enabled: false
\ No newline at end of file
diff --git a/kubernetes-hardening-guide/CTR_KUBERNETES_HARDENING_GUIDANCE_1.2_20220829.PDF b/kubernetes-hardening-guide/CTR_KUBERNETES_HARDENING_GUIDANCE_1.2_20220829.PDF
new file mode 100644
index 00000000..f08ee521
Binary files /dev/null and b/kubernetes-hardening-guide/CTR_KUBERNETES_HARDENING_GUIDANCE_1.2_20220829.PDF differ
diff --git a/nginx-deployment.yaml b/nginx-deployment.yaml
new file mode 100644
index 00000000..33c6ad64
--- /dev/null
+++ b/nginx-deployment.yaml
@@ -0,0 +1,24 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ creationTimestamp: null
+ labels:
+ app: nginx-deployment
+ name: nginx-deployment
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: nginx-deployment
+ strategy: {}
+ template:
+ metadata:
+ creationTimestamp: null
+ labels:
+ app: nginx-deployment
+ spec:
+ containers:
+ - image: nginx
+ name: nginx
+ resources: {}
+status: {}
diff --git a/nginx-pod.yaml b/nginx-pod.yaml
new file mode 100644
index 00000000..6756a983
--- /dev/null
+++ b/nginx-pod.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ creationTimestamp: null
+ labels:
+ run: nginx-pod
+ name: nginx-pod
+spec:
+ containers:
+ - image: nginx
+ name: nginx-pod
+ resources:
+ limits:
+ memory: 512Mi
+ cpu: 500m
+ requests:
+ memory: 256Mi
+ dnsPolicy: ClusterFirst
+ restartPolicy: Always
+status: {}
diff --git a/opensearch-bk/README.md b/opensearch-bk/README.md
new file mode 100644
index 00000000..6a938d22
--- /dev/null
+++ b/opensearch-bk/README.md
@@ -0,0 +1,204 @@
+
+
+
+Table of Contents
+=================
+
+ * [Set up Overview](#set-up-overview)
+ * [Installation](#installation)
+ * [Access the cluster](#access-the-cluster)
+ * [Reference links](#reference-links)
+
+## Set up Overview
+
+For demo purposes, I am using Rancher platform for running kubernetes (v1.24.3) cluster. The Helm chart version used for this demo for Opensearch and OpenSearch Dashboards is 2.8.0 and 2.6.0 respectively. I have created the resources in `opensearch` namespace.
+
+A minimum of 4GiB of memory is required. It is recommended to have 8 GiB of memory available for this setup to avoid any intermittent failures.
+
+Please clone the github repository as we are going to make changes in the `values.yaml` which is located inside **`charts --> opensearch`** folder.
+
+```Shell
+git clone https://github.com/opensearch-project/helm-charts.git
+```
+
+## Installation
+
+To install the OpenSearch Helm charts, execute the following commands:
+
+```
+cd helm-charts/charts/opensearch
+```
+
+Here, we have defined persistent-volume yaml file:
+
+```YAML
+#pv.yaml
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: opensearch-cluster-master-pv-master
+spec:
+ accessModes:
+ - ReadWriteOnce
+ capacity:
+ storage: 8Gi
+ claimRef:
+ apiVersion: v1
+ kind: PersistentVolumeClaim
+ name: opensearch-cluster-master-opensearch-cluster-master-0
+ namespace: opensearch
+ hostPath:
+ path: /tmp/mypvsc
+ type: DirectoryOrCreate
+ persistentVolumeReclaimPolicy: Delete
+ storageClassName: local-path
+ volumeMode: Filesystem
+```
+
+```
+k apply -f pv.yaml
+```
+
+You can use vim editor or any text editor of your choice. Here, I have used visual studio code to edit the `values.yaml` file.
+
+We are creating a single replica of opensearch so we have changed configuration for `singleNode` to `true` from `false` and `replicas` to `1` from `3` in `values.yaml` file.
+
+Please save and close the `values.yaml`
+
+To install the OpenSearch Helm charts, execute the following commands:
+
+```
+helm repo add opensearch https://opensearch-project.github.io/helm-charts/
+```
+
+```
+helm repo update
+```
+
+You can now deploy charts with this command.
+
+```shell
+ helm install opensearch-master . -f values.yaml
+```
+
+Please run following command to get the status of `opensearch-cluster-master` StatefulSet and pod:
+
+```
+kubectl get sts
+```
+
+```
+NAME READY AGE
+opensearch-cluster-master 1/1 1m
+```
+
+```
+kubectl get pod
+```
+
+```
+NAME READY STATUS RESTARTS AGE
+opensearch-cluster-master-0 1/1 Running 0 1m
+```
+
+We have installed **`OpenSearch Dashboards`** with the `default` configuration by doing a Helm install.
+
+```
+helm install dashboards opensearch/opensearch-dashboards
+```
+
+Please run following command to get the status of `opensearch-dashboards` deployment and pod:
+
+```
+kubectl get deployments
+```
+
+```
+NAME READY UP-TO-DATE AVAILABLE AGE
+dashboards-opensearch-dashboards 1/1 1 1 2m
+```
+
+```
+kubectl get pods
+```
+
+```
+NAME READY STATUS RESTARTS AGE
+dashboards-opensearch-dashboards-74995cf479-jhct9 1/1 Running 0 2m
+opensearch-cluster-master-0 1/1 Running 0 1m
+```
+
+## Access the cluster
+
+1. To access the cluster locally use `kubectl` to forward it to port 9200 using the below command.
+
+```
+ kubectl port-forward opensearch-cluster-master-0 9200
+```
+
+2. Open a different tab in the terminal and run the following command to check your cluster is spinning
+
+```
+ curl -XGET https://localhost:9200 -u 'admin:admin' --insecure
+```
+
+You can also open a new browser tab and type, https://localhost:9200 in URL box.
+Once asked for credentials, please provide username as `admin` and password as `admin`.
+
+```Output
+{
+ "name" : "opensearch-cluster-master-0",
+ "cluster_name" : "opensearch-cluster",
+ "cluster_uuid" : "se6VXgQESmWGeR9Jf7Yciw",
+ "version" : {
+ "distribution" : "opensearch",
+ "number" : "2.4.0",
+ "build_type" : "tar",
+ "build_hash" : "744ca260b892d119be8164f48d92b8810bd7801c",
+ "build_date" : "2022-11-15T04:42:29.671309257Z",
+ "build_snapshot" : false,
+ "lucene_version" : "9.4.1",
+ "minimum_wire_compatibility_version" : "7.10.0",
+ "minimum_index_compatibility_version" : "7.0.0"
+ },
+ "tagline" : "The OpenSearch Project: https://opensearch.org/"
+}
+```
+
+3. To access the OpenSearch Dashboards URL locally, forward it to port 5601.
+
+```
+ kubectl get pods
+```
+
+```
+NAME READY STATUS RESTARTS AGE
+dashboards-opensearch-dashboards-74995cf479-jhct9 1/1 Running 0 2m
+opensearch-cluster-master-0 1/1 Running 0 1m
+```
+
+After getting the pod name do a `port-forward` to 5601 by running the following command:
+
+```
+kubectl port-forward dashboards-opensearch-dashboards-74995cf479-jhct9 5601
+```
+
+4. Visit this URL http://localhost:5601/ and use username and password as “admin” to login and view OpenSearch Dashboards.
+5. We can `Cancel` or `close` the next pop-up for `Select your tenant`.
+6. Click on Menu button (hamburger button) on top left side, Navigate to `Management` > `Stack Management` > `Index Patterns` and follow below images for the next steps:
+
+![Create-Index-Pattern-Opensearch](/images/Create-Index-Pattern-Opensearch.png)
+
+![Defined-Index-Pattern-Opensearch](/images/Defined-Index-Pattern-Opensearch.png)
+
+![Defined-Index-Pattern-2-Opensearch](/images/Defined-Index-Pattern-2-Opensearch.png)
+
+7. Go to the **OpenSearch Dashboards** > **Discover** to visualize the logs:
+![Discover-logs-Opensearch](/images/Discover-logs-Opensearch.png)
+
+## Reference links
+
+[Setup OpenSearch multi-node cluster on Kubernetes using Helm Charts](https://opensearch.org/blog/technical-posts/2021/11/setup-multinode-cluster-kubernetes/)
+
+[OpenSearch helm charts](https://github.com/opensearch-project/helm-charts)
+
diff --git a/opensearch-bk/helm-charts/.gitignore b/opensearch-bk/helm-charts/.gitignore
new file mode 100644
index 00000000..48336707
--- /dev/null
+++ b/opensearch-bk/helm-charts/.gitignore
@@ -0,0 +1,5 @@
+# macOS
+.DS_Store
+
+# Windows
+Thumbs.db
diff --git a/opensearch-bk/helm-charts/ADMINS.md b/opensearch-bk/helm-charts/ADMINS.md
new file mode 100644
index 00000000..534cc1be
--- /dev/null
+++ b/opensearch-bk/helm-charts/ADMINS.md
@@ -0,0 +1,7 @@
+## Admins
+
+| Admin | GitHub ID | Affiliation |
+| --------------- | --------------------------------------- | ----------- |
+| Henri Yandell | [hyandell](https://github.com/hyandell) | Amazon |
+
+[This document](https://github.com/opensearch-project/.github/blob/main/ADMINS.md) explains what admins do in this repo. and how they should be doing it. If you're interested in becoming a maintainer, see [MAINTAINERS](MAINTAINERS.md). If you're interested in contributing, see [CONTRIBUTING](CONTRIBUTING.md).
\ No newline at end of file
diff --git a/opensearch-bk/helm-charts/CODE_OF_CONDUCT.md b/opensearch-bk/helm-charts/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..71291884
--- /dev/null
+++ b/opensearch-bk/helm-charts/CODE_OF_CONDUCT.md
@@ -0,0 +1,22 @@
+This code of conduct applies to all spaces provided by the OpenSource project including in code, documentation, issue trackers, mailing lists, chat channels, wikis, blogs, social media and any other communication channels used by the project.
+
+**Our open source communities endeavor to:**
+
+* Be Inclusive: We are committed to being a community where everyone can join and contribute. This means using inclusive and welcoming language.
+* Be Welcoming: We are committed to maintaining a safe space for everyone to be able to contribute.
+* Be Respectful: We are committed to encouraging differing viewpoints, accepting constructive criticism and work collaboratively towards decisions that help the project grow. Disrespectful and unacceptable behavior will not be tolerated.
+* Be Collaborative: We are committed to supporting what is best for our community and users. When we build anything for the benefit of the project, we should document the work we do and communicate to others on how this affects their work.
+
+**Our Responsibility. As contributors, members, or bystanders we each individually have the responsibility to behave professionally and respectfully at all times. Disrespectful and unacceptable behaviors include, but are not limited to:**
+
+* The use of violent threats, abusive, discriminatory, or derogatory language;
+* Offensive comments related to gender, gender identity and expression, sexual orientation, disability, mental illness, race, political or religious affiliation;
+* Posting of sexually explicit or violent content;
+* The use of sexualized language and unwelcome sexual attention or advances;
+* Public or private harassment of any kind;
+* Publishing private information, such as physical or electronic address, without permission;
+* Other conduct which could reasonably be considered inappropriate in a professional setting;
+* Advocating for or encouraging any of the above behaviors.
+* Enforcement and Reporting Code of Conduct Issues:
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported. [Contact us](mailto:opensource-codeofconduct@amazon.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances.
\ No newline at end of file
diff --git a/opensearch-bk/helm-charts/CONTRIBUTING.md b/opensearch-bk/helm-charts/CONTRIBUTING.md
new file mode 100644
index 00000000..1e71929e
--- /dev/null
+++ b/opensearch-bk/helm-charts/CONTRIBUTING.md
@@ -0,0 +1,21 @@
+## Contributing to this Project
+
+- [Contributing to OpenSearch](https://github.com/opensearch-project/.github/blob/main/CONTRIBUTING.md#contributing-to-opensearch)
+ - [First Things First](https://github.com/opensearch-project/.github/blob/main/CONTRIBUTING.md#contributing-to-opensearch)
+ - [Ways to Contribute](https://github.com/opensearch-project/.github/blob/main/CONTRIBUTING.md#ways-to-contribute)
+ - [Bug Reports](https://github.com/opensearch-project/.github/blob/main/CONTRIBUTING.md#bug-reports)
+ - [Feature Requests](https://github.com/opensearch-project/.github/blob/main/CONTRIBUTING.md#feature-requests)
+ - [Documentation Changes](https://github.com/opensearch-project/.github/blob/main/CONTRIBUTING.md#documentation-changes)
+ - [Contributing Code](https://github.com/opensearch-project/.github/blob/main/CONTRIBUTING.md#contributing-code)
+ - [Developer Certificate of Origin](https://github.com/opensearch-project/.github/blob/main/CONTRIBUTING.md#developer-certificate-of-origin)
+ - [Submitting a pull request](#submitting-a-pull-request)
+ - [Review Process](https://github.com/opensearch-project/.github/blob/main/CONTRIBUTING.md#review-process)
+
+ ## Submitting a Pull Request
+
+ Before submitting a pull request make sure you have validated the following:
+ 1. Check the [Version and Branching](https://github.com/opensearch-project/helm-charts/blob/main/README.md#version-and-branching) section before commiting a change through PR.
+ 1. All the individual commits in the PR should be signed off. See DCO [section](https://github.com/opensearch-project/.github/blob/main/CONTRIBUTING.md#developer-certificate-of-origin) for more details.
+ 1. Chart version should be bumped for every code change except docoumentation change. Refer the PR [#179](https://github.com/opensearch-project/helm-charts/pull/179) for an example.
+ 1. Make sure the PR does not have any merge conflicts. If there are any conflicts please rebase your commits over the code in `main` branch.
+ 1. Ensure the linting and testing checks passes once you raise the PR. Unless the lint is passing the PR cannot be merged. You will be able to see the results of the workflows. In case it is failing you can use it to debug further.
diff --git a/opensearch-bk/helm-charts/DEVELOPER_GUIDE.md b/opensearch-bk/helm-charts/DEVELOPER_GUIDE.md
new file mode 100644
index 00000000..fbddf266
--- /dev/null
+++ b/opensearch-bk/helm-charts/DEVELOPER_GUIDE.md
@@ -0,0 +1,15 @@
+- [Developer Guide](#developer-guide)
+ - [Forking and Cloning](#forking-and-cloning)
+ - [Submitting Changes](#submitting-changes)
+
+## Developer Guide
+
+So you want to contribute code to this project? Excellent! We're glad you're here. Here's what you need to do.
+
+### Forking and Cloning
+
+Fork this repository on GitHub, and clone locally with `git clone`.
+
+### Submitting Changes
+
+See [CONTRIBUTING](CONTRIBUTING.md).
\ No newline at end of file
diff --git a/opensearch-bk/helm-charts/LICENSE.txt b/opensearch-bk/helm-charts/LICENSE.txt
new file mode 100644
index 00000000..67db8588
--- /dev/null
+++ b/opensearch-bk/helm-charts/LICENSE.txt
@@ -0,0 +1,175 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
diff --git a/opensearch-bk/helm-charts/MAINTAINERS.md b/opensearch-bk/helm-charts/MAINTAINERS.md
new file mode 100644
index 00000000..9aca7d07
--- /dev/null
+++ b/opensearch-bk/helm-charts/MAINTAINERS.md
@@ -0,0 +1,12 @@
+## Maintainers
+
+| Maintainer | GitHub ID | Affiliation |
+| --------------- | --------- | ----------- |
+| Barani Bikshandi | [bbarani](https://github.com/bbarani) | Amazon |
+| Peter Zhu | [peterzhuamazon](https://github.com/peterzhuamazon) | Amazon |
+| Sayali Gaikawad | [gaiksaya](https://github.com/gaiksaya) | Amazon |
+| Prudhvi Godithi | [prudhvigodithi](https://github.com/prudhvigodithi) | Amazon |
+| Dhiraj Kumar Jain | [TheAlgo](https://github.com/TheAlgo) | Amazon |
+| Aaron Layfield | [DandyDeveloper](https://github.com/DandyDeveloper) | Community |
+
+[This document](https://github.com/opensearch-project/.github/blob/main/MAINTAINERS.md) explains what maintainers do in this repo, and how they should be doing it. If you're interested in contributing, see [CONTRIBUTING](CONTRIBUTING.md).
diff --git a/opensearch-bk/helm-charts/README.md b/opensearch-bk/helm-charts/README.md
new file mode 100644
index 00000000..79c2e2a6
--- /dev/null
+++ b/opensearch-bk/helm-charts/README.md
@@ -0,0 +1,97 @@
+
+
+- [OpenSearch Project Helm-Charts](#helm-charts)
+- [Status](#status)
+- [Version and Branching](#version-and-branching)
+- [Installation](#installation)
+- [Change Logs](#change-logs)
+- [Contributing](#contributing)
+- [Getting Help](#getting-help)
+- [Code of Conduct](#code-of-conduct)
+- [Security](#security)
+- [License](#license)
+
+## Helm-Charts
+
+A community repository for Helm Charts of OpenSearch Project.
+
+## Status
+
+[![Lint and Test Charts](https://github.com/opensearch-project/helm-charts/actions/workflows/lint-test.yaml/badge.svg)](https://github.com/opensearch-project/helm-charts/actions/workflows/lint-test.yaml)
+ [![Release Charts](https://github.com/opensearch-project/helm-charts/actions/workflows/release.yaml/badge.svg)](https://github.com/opensearch-project/helm-charts/actions/workflows/release.yaml)
+
+## Version and Branching
+As of now, this helm-charts repository maintains 3 branches:
+* _main_ (Version is 2.x.x for both `version` and `appVersion` in `Chart.yaml`)
+* _1.x_ (Version is 1.x.x for both `version` and `appVersion` in `Chart.yaml`)
+* _gh-pages_ (Reserved branch for publishing helm-charts through github pages)
+
+
+Contributors should choose the corresponding branch(es) when commiting their change(s):
+* If you have a change for a specific version, only open PR to specific branch
+* If you have a change for all available versions, first open a PR on `main`, then open a backport PR with `[backport 1.x]` in the title, with label `backport 1.x`, etc.
+* No changes should be commited to `gh-pages` by any contributor, as this branch should be only changed by github actions `chart-releaser`
+
+## Installation
+
+To install the OpenSearch Helm charts, execute the following commands:
+
+```shell
+helm repo add opensearch https://opensearch-project.github.io/helm-charts/
+helm repo update
+```
+
+Once the charts repository reference is added, you can run the following command to see the charts.
+
+```shell
+helm search repo opensearch
+```
+
+You can now deploy charts with this command.
+
+```shell
+helm install my-deployment opensearch/
+```
+
+Please see the `README.md` in the [OpenSearch](charts/opensearch) and [OpenSearch Dashboards](charts/opensearch-dashboards) directories for installation instructions.
+
+### Notes About Default Installation
+
+By default, on startup, the `install_demo_configuration.sh` is runned via the `opensearch-docker-entrypoint.sh` script if `DISABLE_INSTALL_DEMO_CONFIG` is not `true`.
+
+In case custom certificates are used and `allow_unsafe_democertificates` is set to `false` in the configuration, this can prevent pods to start with the following error: `Demo certificates found but plugins.security.allow_unsafe_democertificates is set to false.`
+
+This can be solved by adding an environment variable in the `value.yml`:
+```
+extraEnvs:
+ - name: DISABLE_INSTALL_DEMO_CONFIG
+ value: "true"
+```
+
+## Change Logs
+
+Please review the [OpenSearch](charts/opensearch/CHANGELOG.md) and the
+[OpenSearch Dashboards](charts/opensearch-dashboards/CHANGELOG.md) change logs for the latest
+release details.
+
+## Contributing
+
+See [developer guide](DEVELOPER_GUIDE.md) and [how to contribute to this project](CONTRIBUTING.md).
+
+## Getting Help
+
+If you find a bug, or have a feature request, please don't hesitate to open an issue in this repository.
+
+For more information, see [project website](https://opensearch.org/) and [documentation](https://opensearch.org/docs). If you need help and are unsure where to open an issue, try [forums](https://discuss.opendistrocommunity.dev/).
+
+## Code of Conduct
+
+This project has adopted the [Amazon Open Source Code of Conduct](CODE_OF_CONDUCT.md). For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq), or contact [opensource-codeofconduct@amazon.com](mailto:opensource-codeofconduct@amazon.com) with any additional questions or comments.
+
+## Security
+
+If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public GitHub issue.
+
+## License
+
+This project is licensed under the [Apache v2.0 License](LICENSE.txt).
diff --git a/opensearch-bk/helm-charts/charts/README.md b/opensearch-bk/helm-charts/charts/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/.helmignore b/opensearch-bk/helm-charts/charts/opensearch-dashboards/.helmignore
new file mode 100644
index 00000000..0e8a0eb3
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/.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/opensearch-bk/helm-charts/charts/opensearch-dashboards/CHANGELOG.md b/opensearch-bk/helm-charts/charts/opensearch-dashboards/CHANGELOG.md
new file mode 100644
index 00000000..5776ebc4
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/CHANGELOG.md
@@ -0,0 +1,185 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+---
+## [Unreleased]
+### Added
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.6.0]
+### Added
+### Changed
+- Updated OpenSearch Dashboards appVersion to 2.4.0
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.5.3]
+### Added
+- Startup, readiness and liveness probes for deployment
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.5.2]
+### Added
+- Template configmap content by tpl function
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.5.1]
+### Added
+### Changed
+### Deprecated
+### Removed
+### Fixed
+- ingress helm validation error fix by removing additional hyphen
+### Security
+---
+## [2.5.0]
+### Added
+### Changed
+- Updated version to 2.5.0 and appVersion to "2.3.0".
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.4.2]
+### Added
+### Changed
+### Deprecated
+### Removed
+### Fixed
+- OpenSearch Dashboards fixed failure when ingress service port is a string (named port)
+### Security
+---
+## [2.4.1]
+### Added
+- Helm chart-releaser parallel release issue, updated version to 2.4.1.
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.4.0]
+### Added
+- Updated version to 2.4.0 and appVersion to "2.2.1".
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.3.0]
+### Added
+- Updated version to 2.3.0 and appVersion to "2.2.0".
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.2.4]
+### Added
+- Add lifecycle hooks for opensearch-dashboards charts
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.2.3]
+### Added
+### Changed
+### Deprecated
+### Removed
+### Fixed
+- Opensearch dashboards ingress template to use values from provided config
+### Security
+---
+## [2.2.2]
+### Added
+### Changed
+### Deprecated
+### Removed
+### Fixed
+- Opensearch dashboard fix issue #295.
+- Opensearch dashboard config map support both string and map format.
+### Security
+---
+## [2.2.1]
+### Added
+### Changed
+### Deprecated
+### Removed
+### Fixed
+- Opensearch dashboard config map format is restored with backward support of string format
+### Security
+---
+## [2.2.0]
+### Added
+### Changed
+- Updated version to 2.2.0 and appVersion to "2.1.0".
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.1.0]
+### Added
+### Changed
+- Updated version to 2.1.0 and appVersion to "2.0.1".
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.0.1]
+### Added
+### Changed
+- Updated version to 2.0.1 and appVersion to "2.0.0".
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.0.0]
+### Added
+### Changed
+- Updated version to 2.0.0 and appVersion to "2.0.0-rc1".
+### Deprecated
+### Removed
+### Fixed
+### Security
+
+[Unreleased]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.6.0...HEAD
+[2.6.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.5.3...opensearch-dashboards-2.6.0
+[2.5.3]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.5.2...opensearch-dashboards-2.5.3
+[2.5.2]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.5.1...opensearch-dashboards-2.5.2
+[2.5.1]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.5.0...opensearch-dashboards-2.5.1
+[2.5.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.4.1...opensearch-dashboards-2.5.0
+[2.4.1]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.4.0...opensearch-dashboards-2.4.1
+[2.4.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.3.0...opensearch-dashboards-2.4.0
+[2.3.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.2.4...opensearch-dashboards-2.3.0
+[2.2.4]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.2.3...opensearch-dashboards-2.2.4
+[2.2.3]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.2.2...opensearch-dashboards-2.2.3
+[2.2.2]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.2.1...opensearch-dashboards-2.2.2
+[2.2.1]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.2.0...opensearch-dashboards-2.2.1
+[2.2.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.1.0...opensearch-dashboards-2.2.0
+[2.1.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.0.1...opensearch-dashboards-2.1.0
+[2.0.1]: https://github.com/opensearch-project/helm-charts/compare/opensearch-dashboards-2.0.0...opensearch-dashboards-2.0.1
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/Chart.yaml b/opensearch-bk/helm-charts/charts/opensearch-dashboards/Chart.yaml
new file mode 100644
index 00000000..21e30b71
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/Chart.yaml
@@ -0,0 +1,32 @@
+apiVersion: v2
+name: opensearch-dashboards
+description: A Helm chart for OpenSearch Dashboards
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 2.6.0
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application. Versions are not expected to
+# follow Semantic Versioning. They should reflect the version the application is using.
+# It is recommended to use it with quotes.
+appVersion: "2.4.0"
+
+maintainers:
+ - name: DandyDeveloper
+ - name: bbarani
+ - name: gaiksaya
+ - name: peterzhuamazon
+ - name: prudhvigodithi
+ - name: TheAlgo
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/README.md b/opensearch-bk/helm-charts/charts/opensearch-dashboards/README.md
new file mode 100644
index 00000000..d951abae
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/README.md
@@ -0,0 +1,89 @@
+# OpenSearch Dashboards Helm Chart
+
+ This Helm chart installs [OpenSearch Dashboards](https://github.com/opensearch-project/OpenSearch-Dashboards) with configurable TLS, RBAC and much more configurations. This chart caters to a number of different use cases and setups.
+
+ - [Requirements](#requirements)
+ - [Installing](#installing)
+ - [Uninstalling](#uninstalling)
+
+ ## Requirements
+
+ * Kubernetes >= 1.14
+ * Helm >= 2.17.0
+ * We recommend you to have 8 GiB of memory available for this deployment, or at least 4 GiB for the minimum requirement. Else, the deployment is expected to fail.
+
+ ## Installing
+
+ Once you've added this Helm repository as per the repository-level [README](../../README.md#installing)
+ then you can install the chart as follows:
+
+ ```shell
+ helm install my-release opensearch/opensearch-dashboards
+```
+
+ The command deploys OpenSearch Dashboards with its associated components on the Kubernetes cluster in the default configuration.
+
+ **NOTE:** If using Helm 2 then you'll need to add the [`--name`](https://v2.helm.sh/docs/helm/#options-21) command line argument. If unspecified, Helm 2 will autogenerate a name for you.
+
+ ## Uninstalling
+ To delete/uninstall the chart with the release name `my-release`:
+
+ ```shell
+ helm uninstall my-release
+ ```
+
+## Configuration
+
+| Parameter | Description | Default |
+|------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------|
+| `envFrom` | Templatable string to be passed to the [environment from variables][] which will be appended to the `envFrom:` definition for the container | `[]` |
+| `config` | Allows you to add any config files in `/usr/share/opensearch-dashboards/` such as `opensearch_dashboards.yml`. String or map format may be used for specifying content of each configuration file. In case of string format, the whole content of the config file will be replaced by new config file value when in case of using map format content of configuration file will be a result of merge. In both cases content passed through tpl. See [values.yaml][] for an example of the formatting | `{}` |
+| `extraContainers` | Array of extra containers | `""` |
+| `extraEnvs` | Extra environments variables to be passed to OpenSearch services | `[]` |
+| `extraInitContainers` | Array of extra init containers | `[]` |
+| `extraVolumeMounts` | Array of extra volume mounts | `[] ` |
+| `extraVolumes` | Array of extra volumes to be added | `[]` |
+| `fullnameOverride` | Overrides the `clusterName` and `nodeGroup` when used in the naming of resources. This should only be used when using a single `nodeGroup`, otherwise you will have name conflicts | `""` |
+| `hostAliases` | Configurable [hostAliases][] | `[]` |
+| `image.pullPolicy` | The Kubernetes [imagePullPolicy][] value | `IfNotPresent` |
+| `imagePullSecrets` | Configuration for [imagePullSecrets][] so that you can use a private registry for your image | `[]` |
+| `image.tag` | The OpenSearch Docker image tag | `1.0.0` |
+| `image.repository` | The OpenSearch Docker image | `opensearchproject/opensearch` |
+| `ingress` | Configurable [ingress][] to expose the OpenSearch service. See [values.yaml][] for an example | see [values.yaml][] |
+| `labels` | Configurable [labels][] applied to all OpenSearch pods | `{}` |
+| `lifecycle` | Allows you to add [lifecycle hooks](https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/). See [values.yaml][] for an example | `{}` |
+| `nameOverride` | Overrides the `clusterName` when used in the naming of resources | `""` |
+| `nodeSelector` | Configurable [nodeSelector][] so that you can target specific nodes for your OpenSearch cluster | `{}` |
+| `podAnnotations` | Configurable [annotations][] applied to all OpenSearch pods | `{}` |
+| `podSecurityContext` | Allows you to set the [securityContext][] for the pod | see [values.yaml][] |
+| `priorityClassName` | The name of the [PriorityClass][]. No default is supplied as the PriorityClass must be created first | `""` | |
+| `rbac` | Configuration for creating a role, role binding and ServiceAccount as part of this Helm chart with `create: true`. Also can be used to reference an external ServiceAccount with `serviceAccountName: "externalServiceAccountName"` | see [values.yaml][] |
+| `resources` | Allows you to set the [resources][] for the StatefulSet | see [values.yaml][] |
+| `secretMounts` | Allows you easily mount a secret as a file inside the StatefulSet. Useful for mounting certificates and other secrets. See [values.yaml][] for an example | `[]` |
+| `securityContext` | Allows you to set the [securityContext][] for the container | see [values.yaml][] |
+| `service.annotations` | [LoadBalancer annotations][] that Kubernetes will use for the service. This will configure load balancer if `service.type` is `LoadBalancer` | `{}` |
+| `service.headless.annotations` | Allow you to set annotations on the headless service | `{}` |
+| `service.externalTrafficPolicy` | Some cloud providers allow you to specify the [LoadBalancer externalTrafficPolicy][]. Kubernetes will use this to preserve the client source IP. This will configure load balancer if `service.type` is `LoadBalancer` | `""` |
+| `service.httpPortName` | The name of the http port within the service | `http` |
+| `service.labelsHeadless` | Labels to be added to headless service | `{}` |
+| `service.labels` | Labels to be added to non-headless service | `{}` |
+| `service.loadBalancerIP` | Some cloud providers allow you to specify the [loadBalancer][] IP. If the `loadBalancerIP` field is not specified, the IP is dynamically assigned. If you specify a `loadBalancerIP` but your cloud provider does not support the feature, it is ignored. | `""` |
+| `service.loadBalancerSourceRanges` | The IP ranges that are allowed to access | `[]` |
+| `service.nodePort` | Custom [nodePort][] port that can be set if you are using `service.type: nodePort` | `""` |
+| `service.transportPortName` | The name of the transport port within the service | `transport` |
+| `service.type` | OpenSearch [Service Types][] | `ClusterIP` |
+| `tolerations` | Configurable [tolerations][] | `[]` |
+| `updateStrategy` | The [updateStrategy][] for the StatefulSet. By default Kubernetes will wait for the cluster to be green after upgrading each pod. Setting this to `OnDelete` will allow you to manually delete each pod during upgrades | `RollingUpdate` |
+| `extraObjects` | Array of extra K8s manifests to deploy | list `[]` |
+| `autoscaling` | Prerequisite: Install/Configure metrics server, to install use `kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml`, See https://github.com/kubernetes-sigs/metrics-server. Configurable pod autoscaling stratergy to scale based on `targetCPUUtilizationPercentage`, configure `minReplicas` and `maxReplicas` for desired scaling | false |
+| `livenessProbe` | Configuration fields for the liveness [probe][] | see [exampleLiveness][] in `values.yaml`
+| `readinessProbe` | Configuration fields for the readiness [probe][] | see [exampleReadiness][] in `values.yaml`
+| `startupProbe` | Configuration fields for the startup [probe][] | see [exampleStartup][] in `values.yaml` |
+
+
+[probe]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes
+
+
+[exampleStartup]: https://github.com/opensearch-project/helm-charts/blob/main/charts/opensearch-dashboards/values.yaml#17
+[exampleLiveness]: https://github.com/opensearch-project/helm-charts/blob/main/charts/opensearch-dashboards/values.yaml#27
+[exampleReadiness]: https://github.com/opensearch-project/helm-charts/blob/main/charts/opensearch-dashboards/values.yaml#37
\ No newline at end of file
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/NOTES.txt b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/NOTES.txt
new file mode 100644
index 00000000..d92acdc5
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/NOTES.txt
@@ -0,0 +1,22 @@
+1. Get the application URL by running these commands:
+{{- if .Values.ingress.enabled }}
+{{- range $host := .Values.ingress.hosts }}
+ {{- range .paths }}
+ http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
+ {{- end }}
+{{- end }}
+{{- else if contains "NodePort" .Values.service.type }}
+ export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "opensearch-dashboards.fullname" . }})
+ export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+ echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+ NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+ You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "opensearch-dashboards.fullname" . }}'
+ export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "opensearch-dashboards.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+ echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+ export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "opensearch-dashboards.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+ export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
+ echo "Visit http://127.0.0.1:8080 to use your application"
+ kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
+{{- end }}
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/_helpers.tpl b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/_helpers.tpl
new file mode 100644
index 00000000..6c4b60ba
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/_helpers.tpl
@@ -0,0 +1,88 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "opensearch-dashboards.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 "opensearch-dashboards.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 "opensearch-dashboards.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "opensearch-dashboards.labels" -}}
+helm.sh/chart: {{ include "opensearch-dashboards.chart" . }}
+{{ include "opensearch-dashboards.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "opensearch-dashboards.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "opensearch-dashboards.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "opensearch-dashboards.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+ {{- default (include "opensearch-dashboards.fullname" .) .Values.serviceAccount.name }}-dashboards
+{{- else }}
+ {{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
+
+{{/*
+Return the appropriate apiVersion for ingress.
+*/}}
+{{- define "opensearch-dashboards.ingress.apiVersion" -}}
+ {{- if and (.Capabilities.APIVersions.Has "networking.k8s.io/v1") (semverCompare ">= 1.19-0" .Capabilities.KubeVersion.Version) -}}
+ {{- print "networking.k8s.io/v1" -}}
+ {{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
+ {{- print "networking.k8s.io/v1beta1" -}}
+ {{- else -}}
+ {{- print "extensions/v1beta1" -}}
+ {{- end -}}
+{{- end -}}
+
+{{/*
+Return if ingress is stable.
+*/}}
+{{- define "opensearch-dashboards.ingress.isStable" -}}
+ {{- eq (include "opensearch-dashboards.ingress.apiVersion" .) "networking.k8s.io/v1" -}}
+{{- end -}}
+{{/*
+Return if ingress supports ingressClassName.
+*/}}
+{{- define "opensearch-dashboards.ingress.supportsIngressClassName" -}}
+ {{- or (eq (include "opensearch-dashboards.ingress.isStable" .) "true") (and (eq (include "opensearch-dashboards.ingress.apiVersion" .) "networking.k8s.io/v1beta1") (semverCompare ">= 1.18-0" .Capabilities.KubeVersion.Version)) -}}
+{{- end -}}
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/autoscaler.yaml b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/autoscaler.yaml
new file mode 100644
index 00000000..be628442
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/autoscaler.yaml
@@ -0,0 +1,15 @@
+{{- if .Values.autoscaling.enabled -}}
+apiVersion: autoscaling/v1
+kind: HorizontalPodAutoscaler
+metadata:
+ name: {{ template "opensearch-dashboards.fullname" . }}-hpa
+ labels: {{- include "opensearch-dashboards.labels" . | nindent 4 }}
+spec:
+ maxReplicas: {{ .Values.autoscaling.maxReplicas }}
+ minReplicas: {{ .Values.autoscaling.minReplicas }}
+ scaleTargetRef:
+ apiVersion: apps/v1
+ kind: Deployment
+ name: {{ template "opensearch-dashboards.fullname" . }}
+ targetCPUUtilizationPercentage: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
+{{- end }}
\ No newline at end of file
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/configmap.yaml b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/configmap.yaml
new file mode 100644
index 00000000..ce335863
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/configmap.yaml
@@ -0,0 +1,16 @@
+{{- if .Values.config -}}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ template "opensearch-dashboards.fullname" . }}-config
+ labels: {{ include "opensearch-dashboards.labels" . | nindent 4 }}
+data:
+{{- range $configName, $configYaml := .Values.config }}
+ {{ $configName }}: |
+ {{- if eq (kindOf $configYaml) "map" }}
+ {{- tpl (toYaml $configYaml) $ | nindent 4 }}
+ {{- else }}
+ {{- tpl $configYaml $ | nindent 4 -}}
+ {{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/deployment.yaml b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/deployment.yaml
new file mode 100644
index 00000000..e253e64b
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/deployment.yaml
@@ -0,0 +1,192 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ template "opensearch-dashboards.fullname" . }}
+ labels: {{- include "opensearch-dashboards.labels" . | nindent 4 }}
+spec:
+ replicas: {{ .Values.replicaCount }}
+ strategy:
+{{ toYaml .Values.updateStrategy | indent 4 }}
+ selector:
+ matchLabels:
+ app: {{ .Chart.Name }}
+ release: {{ .Release.Name | quote }}
+ template:
+ metadata:
+ labels:
+ app: {{ .Chart.Name }}
+ release: {{ .Release.Name | quote }}
+ {{- range $key, $value := .Values.labels }}
+ {{ $key }}: {{ $value | quote }}
+ {{- end }}
+ annotations:
+ {{- range $key, $value := .Values.podAnnotations }}
+ {{ $key }}: {{ $value | quote }}
+ {{- end }}
+ {{- /* This forces a restart if the configmap has changed */}}
+ {{- if .Values.config }}
+ configchecksum: {{ include (print .Template.BasePath "/configmap.yaml") . | sha256sum | trunc 63 }}
+ {{- end }}
+ spec:
+{{- if .Values.priorityClassName }}
+ priorityClassName: {{ .Values.priorityClassName }}
+{{- end }}
+ securityContext:
+{{ toYaml .Values.podSecurityContext | indent 8 }}
+ serviceAccountName: {{ template "opensearch-dashboards.serviceAccountName" . }}
+ {{- if .Values.hostAliases }}
+ hostAliases: {{ toYaml .Values.hostAliases | nindent 6 }}
+ {{- end }}
+ volumes:
+ {{- range .Values.secretMounts }}
+ - name: {{ .name }}
+ secret:
+ secretName: {{ .secretName }}
+ {{- end }}
+ {{- if .Values.config }}
+ - name: config
+ configMap:
+ name: {{ template "opensearch-dashboards.fullname" . }}-config
+ {{- end }}
+ {{- if .Values.extraVolumes }}
+ # Currently some extra blocks accept strings
+ # to continue with backwards compatibility this is being kept
+ # whilst also allowing for yaml to be specified too.
+ {{- if eq "string" (printf "%T" .Values.extraVolumes) }}
+{{ tpl .Values.extraVolumes . | indent 8 }}
+ {{- else }}
+{{ toYaml .Values.extraVolumes | indent 8 }}
+ {{- end }}
+ {{- end }}
+ {{- with .Values.nodeSelector }}
+ nodeSelector:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ {{- with .Values.affinity }}
+ affinity:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ {{- with .Values.tolerations }}
+ tolerations:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ {{- if .Values.imagePullSecrets }}
+ imagePullSecrets:
+{{ toYaml .Values.imagePullSecrets | indent 8 }}
+ {{- end }}
+ {{- if .Values.extraInitContainers }}
+ # Currently some extra blocks accept strings
+ # to continue with backwards compatibility this is being kept
+ # whilst also allowing for yaml to be specified too.
+ initContainers:
+ {{- if eq "string" (printf "%T" .Values.extraInitContainers) }}
+{{ tpl .Values.extraInitContainers . | indent 6 }}
+ {{- else }}
+{{ toYaml .Values.extraInitContainers | indent 6 }}
+ {{- end }}
+ {{- end }}
+ containers:
+ - name: dashboards
+ securityContext:
+{{ toYaml .Values.securityContext | indent 10 }}
+ image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+ imagePullPolicy: "{{ .Values.image.pullPolicy }}"
+ {{- if .Values.readinessProbe }}
+ readinessProbe:
+{{ toYaml .Values.readinessProbe | indent 10 }}
+ {{- end }}
+ {{- if .Values.livenessProbe }}
+ livenessProbe:
+{{ toYaml .Values.livenessProbe | indent 10 }}
+ {{- end }}
+ {{- if semverCompare ">=1.16-0" .Capabilities.KubeVersion.Version }}
+ {{- if .Values.readinessProbe }}
+ startupProbe:
+{{ toYaml .Values.startupProbe | indent 10 }}
+ {{- end }}
+ {{- end }}
+ env:
+ {{- if .Values.opensearchURL }}
+ - name: OPENSEARCH_URL
+ value: "{{ .Values.opensearchURL }}"
+ {{- else if .Values.opensearchHosts }}
+ - name: OPENSEARCH_HOSTS
+ value: "{{ .Values.opensearchHosts }}"
+ {{- end }}
+ - name: SERVER_HOST
+ value: "{{ .Values.serverHost }}"
+ {{- if .Values.opensearchAccount.secret }}
+ - name: OPENSEARCH_USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.opensearchAccount.secret }}
+ key: username
+ - name: OPENSEARCH_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.opensearchAccount.secret }}
+ key: password
+ {{- if and .Values.opensearchAccount.keyPassphrase.enabled }}
+ - name: KEY_PASSPHRASE
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.opensearchAccount.secret }}
+ key: keypassphrase
+ # 32-character random string to be used as cookie password by security plugin
+ {{- end }}
+ - name: COOKIE_PASS
+ valueFrom:
+ secretKeyRef:
+ name: {{ .Values.opensearchAccount.secret }}
+ key: cookie
+ {{- end }}
+{{- if .Values.extraEnvs }}
+{{ toYaml .Values.extraEnvs | indent 8 }}
+{{- end }}
+{{- if .Values.envFrom }}
+ envFrom:
+{{ toYaml .Values.envFrom | indent 10 }}
+{{- end }}
+ ports:
+ - containerPort: {{ .Values.service.port }}
+ name: {{ .Values.service.httpPortName | default "http" }}
+ protocol: TCP
+{{- if .Values.lifecycle }}
+ lifecycle:
+{{ toYaml .Values.lifecycle | indent 10 }}
+{{- end }}
+ resources:
+{{ toYaml .Values.resources | indent 10 }}
+ volumeMounts:
+ {{- range .Values.secretMounts }}
+ - name: {{ .name }}
+ mountPath: {{ .path }}
+ {{- if .subPath }}
+ subPath: {{ .subPath }}
+ {{- end }}
+ {{- end }}
+ {{- range $path, $config := .Values.config }}
+ - name: config
+ mountPath: /usr/share/opensearch-dashboards/config/{{ $path }}
+ subPath: {{ $path }}
+ {{- end }}
+ {{- if .Values.extraVolumeMounts }}
+ # Currently some extra blocks accept strings
+ # to continue with backwards compatibility this is being kept
+ # whilst also allowing for yaml to be specified too.
+ {{- if eq "string" (printf "%T" .Values.extraVolumeMounts) }}
+{{ tpl .Values.extraVolumeMounts . | indent 10 }}
+ {{- else }}
+{{ toYaml .Values.extraVolumeMounts | indent 10 }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.extraContainers }}
+ # Currently some extra blocks accept strings
+ # to continue with backwards compatibility this is being kept
+ # whilst also allowing for yaml to be specified too.
+ {{- if eq "string" (printf "%T" .Values.extraContainers) }}
+{{ tpl .Values.extraContainers . | indent 6 }}
+ {{- else }}
+{{ toYaml .Values.extraContainers | indent 6 }}
+ {{- end }}
+ {{- end }}
\ No newline at end of file
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/extraManifests.yaml b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/extraManifests.yaml
new file mode 100644
index 00000000..2855904e
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/extraManifests.yaml
@@ -0,0 +1,4 @@
+{{ range .Values.extraObjects }}
+---
+{{ tpl (toYaml .) $ }}
+{{ end }}
\ No newline at end of file
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/ingress.yaml b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/ingress.yaml
new file mode 100644
index 00000000..e7c7cfe1
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/ingress.yaml
@@ -0,0 +1,69 @@
+{{- if .Values.ingress.enabled -}}
+{{- $fullName := include "opensearch-dashboards.fullname" . -}}
+{{- $ingressApiIsStable := eq (include "opensearch-dashboards.ingress.isStable" .) "true" -}}
+{{- $ingressSupportsIngressClassName := eq (include "opensearch-dashboards.ingress.supportsIngressClassName" .) "true" -}}
+{{- $svcPort := .Values.service.port -}}
+{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1
+{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1beta1
+{{- else -}}
+apiVersion: extensions/v1beta1
+{{- end }}
+kind: Ingress
+metadata:
+ name: {{ $fullName }}
+ labels:
+ {{- include "opensearch-dashboards.labels" . | nindent 4 }}
+ {{- with .Values.ingress.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ {{- if and $ingressSupportsIngressClassName .Values.ingress.ingressClassName }}
+ ingressClassName: {{ .Values.ingress.ingressClassName }}
+ {{- end -}}
+ {{- if .Values.ingress.tls }}
+ tls:
+ {{- range .Values.ingress.tls }}
+ - hosts:
+ {{- range .hosts }}
+ - {{ . | quote }}
+ {{- end }}
+ secretName: {{ .secretName }}
+ {{- end }}
+ {{- end }}
+ rules:
+ {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.Version -}}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ .host | quote }}
+ http:
+ paths:
+ {{- range .paths }}
+ - path: {{ .path }}
+ pathType: Prefix
+ backend:
+ service:
+ name: {{ .backend.serviceName | default $fullName }}
+ port:
+ {{- if and .backend.servicePort (kindIs "string" .backend.servicePort) }}
+ name: {{ .backend.servicePort }}
+ {{- else }}
+ number: {{ .backend.servicePort | default $svcPort }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- else -}}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ .host | quote }}
+ http:
+ paths:
+ {{- range .paths }}
+ - path: {{ .path }}
+ backend:
+ serviceName: {{ .backend.serviceName | default $fullName }}
+ servicePort: {{ .backend.servicePort | default $svcPort }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/rolebinding.yaml b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/rolebinding.yaml
new file mode 100644
index 00000000..3fe2a218
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/rolebinding.yaml
@@ -0,0 +1,15 @@
+{{- if .Values.rbac.create -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ labels: {{- include "opensearch-dashboards.labels" . | nindent 4 }}
+ name: {{ template "opensearch-dashboards.fullname" . }}-dashboards-rolebinding
+roleRef:
+ kind: Role
+ name: {{ template "opensearch-dashboards.serviceAccountName" . }}
+ apiGroup: rbac.authorization.k8s.io
+subjects:
+- kind: ServiceAccount
+ name: {{ template "opensearch-dashboards.serviceAccountName" . }}
+ namespace: {{ .Release.Namespace }}
+{{- end }}
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/service.yaml b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/service.yaml
new file mode 100644
index 00000000..ddd66e72
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/service.yaml
@@ -0,0 +1,33 @@
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "opensearch-dashboards.fullname" . }}
+ labels: {{- include "opensearch-dashboards.labels" . | nindent 4 }}
+{{- if .Values.service.labels }}
+{{ toYaml .Values.service.labels | indent 4}}
+{{- end }}
+{{- with .Values.service.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+ type: {{ .Values.service.type }}
+{{- if .Values.service.loadBalancerIP }}
+ loadBalancerIP: {{ .Values.service.loadBalancerIP }}
+{{- end }}
+{{- with .Values.service.loadBalancerSourceRanges }}
+ loadBalancerSourceRanges:
+{{ toYaml . | indent 4 }}
+{{- end }}
+ ports:
+ - port: {{ .Values.service.port }}
+{{- if .Values.service.nodePort }}
+ nodePort: {{ .Values.service.nodePort }}
+{{- end }}
+ protocol: TCP
+ name: {{ .Values.service.httpPortName | default "http" }}
+ targetPort: {{ .Values.service.port }}
+ selector:
+ app: {{ .Chart.Name }}
+ release: {{ .Release.Name | quote }}
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/serviceaccount.yaml b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/serviceaccount.yaml
new file mode 100644
index 00000000..7ffbc076
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/templates/serviceaccount.yaml
@@ -0,0 +1,12 @@
+{{- if .Values.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ include "opensearch-dashboards.serviceAccountName" . }}
+ labels:
+ {{- include "opensearch-dashboards.labels" . | nindent 4 }}
+ {{- with .Values.serviceAccount.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ {{- end }}
diff --git a/opensearch-bk/helm-charts/charts/opensearch-dashboards/values.yaml b/opensearch-bk/helm-charts/charts/opensearch-dashboards/values.yaml
new file mode 100644
index 00000000..c36b1861
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch-dashboards/values.yaml
@@ -0,0 +1,239 @@
+# Copyright OpenSearch Contributors
+# SPDX-License-Identifier: Apache-2.0
+
+# Default values for opensearch-dashboards.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+opensearchHosts: "https://opensearch-cluster-master:9200"
+replicaCount: 1
+
+image:
+ repository: "opensearchproject/opensearch-dashboards"
+ # override image tag, which is .Chart.AppVersion by default
+ tag: ""
+ pullPolicy: "IfNotPresent"
+
+startupProbe:
+ tcpSocket:
+ port: 5601
+ periodSeconds: 10
+ timeoutSeconds: 5
+ failureThreshold: 20
+ successThreshold: 1
+ initialDelaySeconds: 10
+
+livenessProbe:
+ tcpSocket:
+ port: 5601
+ periodSeconds: 20
+ timeoutSeconds: 5
+ failureThreshold: 10
+ successThreshold: 1
+ initialDelaySeconds: 10
+
+readinessProbe:
+ tcpSocket:
+ port: 5601
+ periodSeconds: 20
+ timeoutSeconds: 5
+ failureThreshold: 10
+ successThreshold: 1
+ initialDelaySeconds: 10
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+ # Specifies whether a service account should be created
+ create: true
+ # Annotations to add to the service account
+ annotations: {}
+ # The name of the service account to use.
+ # If not set and create is true, a name is generated using the fullname template
+ name: ""
+
+rbac:
+ create: true
+
+# A list of secrets and their paths to mount inside the pod
+# This is useful for mounting certificates for security and for mounting
+# the X-Pack license
+secretMounts: []
+# - name: certs
+# secretName: dashboard-certs
+# path: /usr/share/dashboards/certs
+
+podAnnotations: {}
+
+extraEnvs: []
+# - name: "NODE_OPTIONS"
+# value: "--max-old-space-size=1800"
+
+envFrom: []
+
+extraVolumes: []
+ # - name: extras
+ # emptyDir: {}
+
+extraVolumeMounts: []
+ # - name: extras
+ # mountPath: /usr/share/extras
+ # readOnly: true
+
+extraInitContainers: ""
+
+extraContainers: ""
+
+podSecurityContext: {}
+
+securityContext:
+ capabilities:
+ drop:
+ - ALL
+ # readOnlyRootFilesystem: true
+ runAsNonRoot: true
+ runAsUser: 1000
+
+config: {}
+ # Default OpenSearch Dashboards configuration from docker image of Dashboards
+
+ # opensearch_dashboards.yml: |
+ # server:
+ # name: dashboards
+ # host: "{{ .Values.serverHost }}"
+
+ # opensearch_dashboards.yml:
+ # server:
+ # name: dashboards
+ # host: "{{ .Values.serverHost }}"
+
+
+ # Dashboards TLS Config (Ensure the cert files are present before enabling SSL
+ # ssl:
+ # enabled: true
+ # key: /usr/share/opensearch-dashboards/certs/dashboards-key.pem
+ # certificate: /usr/share/opensearch-dashboards/certs/dashboards-crt.pem
+
+ # determines how dashboards will verify certificates (needs to be none for default opensearch certificates to work)
+ # opensearch:
+ # ssl:
+ # certificateAuthorities: /usr/share/opensearch-dashboards/certs/dashboards-root-ca.pem
+ # if utilizing custom CA certs for connection to opensearch, provide the CA here
+
+priorityClassName: ""
+
+opensearchAccount:
+ secret: ""
+ keyPassphrase:
+ enabled: false
+
+labels: {}
+
+hostAliases: []
+# - ip: "127.0.0.1"
+# hostnames:
+# - "foo.local"
+# - "bar.local"
+
+serverHost: "0.0.0.0"
+
+service:
+ type: ClusterIP
+ port: 5601
+ loadBalancerIP: ""
+ nodePort: ""
+ labels: {}
+ annotations: {}
+ loadBalancerSourceRanges: []
+ # 0.0.0.0/0
+ httpPortName: http
+
+ingress:
+ enabled: false
+ # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
+ # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
+ # ingressClassName: nginx
+ annotations: {}
+ # kubernetes.io/ingress.class: nginx
+ # kubernetes.io/tls-acme: "true"
+ hosts:
+ - host: chart-example.local
+ paths:
+ - path: /
+ backend:
+ serviceName: ""
+ servicePort: ""
+ tls: []
+ # - secretName: chart-example-tls
+ # hosts:
+ # - chart-example.local
+
+resources:
+ requests:
+ cpu: "100m"
+ memory: "512M"
+ limits:
+ cpu: "100m"
+ memory: "512M"
+
+autoscaling:
+ # This requires metrics server to be installed, to install use kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
+ # See https://github.com/kubernetes-sigs/metrics-server
+ enabled: false
+ minReplicas: 1
+ maxReplicas: 10
+ targetCPUUtilizationPercentage: 80
+
+updateStrategy:
+ type: "Recreate"
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
+
+# -- Array of extra K8s manifests to deploy
+extraObjects: []
+ # - apiVersion: secrets-store.csi.x-k8s.io/v1
+ # kind: SecretProviderClass
+ # metadata:
+ # name: argocd-secrets-store
+ # spec:
+ # provider: aws
+ # parameters:
+ # objects: |
+ # - objectName: "argocd"
+ # objectType: "secretsmanager"
+ # jmesPath:
+ # - path: "client_id"
+ # objectAlias: "client_id"
+ # - path: "client_secret"
+ # objectAlias: "client_secret"
+ # secretObjects:
+ # - data:
+ # - key: client_id
+ # objectName: client_id
+ # - key: client_secret
+ # objectName: client_secret
+ # secretName: argocd-secrets-store
+ # type: Opaque
+ # labels:
+ # app.kubernetes.io/part-of: argocd
+
+# pod lifecycle policies as outlined here:
+# https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks
+lifecycle: {}
+ # preStop:
+ # exec:
+ # command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
+ # postStart:
+ # exec:
+ # command:
+ # - bash
+ # - -c
+ # - |
+ # #!/bin/bash
+ # curl -I "http://admin:admin@127.0.0.1:5601/status -H "kbn-xsrf: true" -H 'kbn-xsrf: true' -H "Content-Type: application/json"
diff --git a/opensearch-bk/helm-charts/charts/opensearch/.helmignore b/opensearch-bk/helm-charts/charts/opensearch/.helmignore
new file mode 100644
index 00000000..0e8a0eb3
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/.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/opensearch-bk/helm-charts/charts/opensearch/CHANGELOG.md b/opensearch-bk/helm-charts/charts/opensearch/CHANGELOG.md
new file mode 100644
index 00000000..bcf32b5a
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/CHANGELOG.md
@@ -0,0 +1,156 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+---
+## [Unreleased]
+### Added
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.8.0]
+### Added
+### Changed
+- Updated OpenSearch appVersion to 2.4.0
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.7.0]
+### Added
+- Add option to enable the use of `sysctlInit` to set sysctl vm.max_map_count through privileged `initContainer`. See: [Issue #87](https://github.com/opensearch-project/helm-charts/issues/87)
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.6.2]
+### Added
+- Liveness probe for statefulset
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.6.1]
+### Added
+- Template configmap content by tpl function
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.6.0]
+### Added
+### Changed
+- Updated version to 2.6.0 and appVersion to "2.3.0".
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.5.1]
+### Added
+- Helm chart-releaser parallel release issue, updated version to 2.5.1.
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.5.0]
+### Added
+- Updated version to 2.5.0 and appVersion to "2.2.1".
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.4.1]
+### Added
+- Add "singleNode" feature to disable the "cluster.initial_master_nodes" env var
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.4.0]
+### Added
+- Updated version to 2.4.0 and appVersion to "2.2.0".
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.3.0]
+### Added
+- Updated version to 2.3.0 and appVersion to "2.1.0".
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.2.0]
+### Added
+- Add feature for readinessProbe and startupProbe
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.1.0]
+### Added
+### Changed
+- Updated version to 2.1.0 and appVersion to "2.0.1".
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.0.1]
+### Added
+### Changed
+- Updated version to 2.0.1 and appVersion to "2.0.0".
+### Deprecated
+### Removed
+### Fixed
+### Security
+---
+## [2.0.0]
+### Added
+### Changed
+- Updated version to 2.0.0 and appVersion to "2.0.0-rc1".
+### Deprecated
+### Removed
+### Fixed
+### Security
+
+
+[Unreleased]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.8.0...HEAD
+[2.8.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.7.0...opensearch-2.8.0
+[2.7.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.6.1...opensearch-2.7.0
+[2.6.2]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.6.1...opensearch-2.6.2
+[2.6.1]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.6.0...opensearch-2.6.1
+[2.6.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.5.0...opensearch-2.6.0
+[2.5.1]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.5.0...opensearch-2.5.1
+[2.5.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.4.1...opensearch-2.5.0
+[2.4.1]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.4.0...opensearch-2.4.1
+[2.4.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.3.0...opensearch-2.4.0
+[2.3.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.2.0...opensearch-2.3.0
+[2.2.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.1.0...opensearch-2.2.0
+[2.1.0]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.0.1...opensearch-2.1.0
+[2.0.1]: https://github.com/opensearch-project/helm-charts/compare/opensearch-2.0.0...opensearch-2.0.1
diff --git a/opensearch-bk/helm-charts/charts/opensearch/Chart.yaml b/opensearch-bk/helm-charts/charts/opensearch/Chart.yaml
new file mode 100644
index 00000000..a0ba8796
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/Chart.yaml
@@ -0,0 +1,32 @@
+apiVersion: v2
+name: opensearch
+description: A Helm chart for OpenSearch
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 2.8.0
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application. Versions are not expected to
+# follow Semantic Versioning. They should reflect the version the application is using.
+# It is recommended to use it with quotes.
+appVersion: "2.4.0"
+
+maintainers:
+ - name: DandyDeveloper
+ - name: bbarani
+ - name: gaiksaya
+ - name: peterzhuamazon
+ - name: prudhvigodithi
+ - name: TheAlgo
diff --git a/opensearch-bk/helm-charts/charts/opensearch/README.md b/opensearch-bk/helm-charts/charts/opensearch/README.md
new file mode 100644
index 00000000..2bfe7100
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/README.md
@@ -0,0 +1,175 @@
+# OpenSearch Helm Chart
+
+This Helm chart installs [OpenSearch](https://github.com/opensearch-project/OpenSearch) with configurable TLS, RBAC and much more configurations. This chart caters a number of different use cases and setups.
+
+- [Requirements](#requirements)
+- [Installing](#installing)
+- [Uninstalling](#uninstalling)
+- [Configuration](#configuration)
+
+## Requirements
+
+* Kubernetes >= 1.14
+* Helm >= 2.17.0
+* We recommend you to have 8 GiB of memory available for this deployment, or at least 4 GiB for the minimum requirement. Else, the deployment is expected to fail.
+
+## Installing
+
+Once you've added this Helm repository as per the repository-level [README](../../README.md#installing) then you can install the chart as follows:
+
+ ```shell
+ helm install my-release opensearch/opensearch
+ ```
+
+The command deploys OpenSearch with its associated components (data statefulsets, masters, clients) on the Kubernetes cluster in the default configuration.
+
+**NOTE:** If using Helm 2 then you'll need to add the [`--name`](https://v2.helm.sh/docs/helm/#options-21) command line argument. If unspecified, Helm 2 will autogenerate a name for you.
+
+## Uninstalling
+To delete/uninstall the chart with the release name `my-release`:
+
+```shell
+helm uninstall my-release
+```
+
+## Configuration
+
+| Parameter | Description | Default |
+|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------|
+| `antiAffinityTopologyKey` | The [anti-affinity][] topology key. By default this will prevent multiple Opensearch nodes from running on the same Kubernetes node | `kubernetes.io/hostname` |
+| `antiAffinity` | Setting this to hard enforces the [anti-affinity][] rules. If it is set to soft it will be done "best effort". Other values will be ignored | `hard` |
+| `clusterName` | This will be used as the OpenSearch cluster name and should be unique per cluster in the namespace | `opensearch-cluster` |
+| `enableServiceLinks` | Set to false to disabling service links, which can cause slow pod startup times when there are many services in the current namespace. | `true` |
+| `envFrom` | Templatable string to be passed to the [environment from variables][] which will be appended to the `envFrom:` definition for the container | `[]` |
+| `config` | Allows you to add any config files in `/usr/share/opensearch/config/` such as `opensearch.yml` and `log4j2.properties`. String or map format may be used for specifying content of each configuration file. In case of string format, the whole content of the config file will be replaced by new config file value when in case of using map format content of configuration file will be a result of merge. In both cases content passed through tpl. See [values.yaml][] for an example of the formatting (passed through tpl) | `{}` |
+| `opensearchJavaOpts` | Java options for OpenSearch. This is where you should configure the jvm heap size | `-Xmx1g -Xms1g` |
+| `majorVersion` | Used to set major version specific configuration. If you are using a custom image and not running the default OpenSearch version you will need to set this to the version you are running (e.g. `majorVersion: 1`) | `""` |
+| `global.dockerRegistry` | Set if you want to change the default docker registry, e.g. a private one. | `""` |
+| `extraContainers` | Array of extra containers | `""` |
+| `extraEnvs` | Extra environments variables to be passed to OpenSearch services | `[]` |
+| `extraInitContainers` | Array of extra init containers | `[]` |
+| `extraVolumeMounts` | Array of extra volume mounts | `[] ` |
+| `extraVolumes` | Array of extra volumes to be added | `[]` |
+| `fullnameOverride` | Overrides the `clusterName` and `nodeGroup` when used in the naming of resources. This should only be used when using a single `nodeGroup`, otherwise you will have name conflicts | `""` |
+| `hostAliases` | Configurable [hostAliases][] | `[]` |
+| `httpPort` | The http port that Kubernetes will use for the healthchecks and the service. If you change this you will also need to set `http.port` in `extraEnvs` | `9200` |
+| `image.pullPolicy` | The Kubernetes [imagePullPolicy][] value | `IfNotPresent` |
+| `imagePullSecrets` | Configuration for [imagePullSecrets][] so that you can use a private registry for your image | `[]` |
+| `image.tag` | The OpenSearch Docker image tag | `1.0.0` |
+| `image.repository` | The OpenSearch Docker image | `opensearchproject/opensearch` |
+| `ingress` | Configurable [ingress][] to expose the OpenSearch service. See [values.yaml][] for an example | see [values.yaml][] |
+| `initResources` | Allows you to set the [resources][] for the `initContainer` in the StatefulSet | `{}` |
+| `keystore` | Allows you map Kubernetes secrets into the keystore. | `[]` |
+| `labels` | Configurable [labels][] applied to all OpenSearch pods | `{}` |
+| `masterService` | The service name used to connect to the masters. You only need to set this if your master `nodeGroup` is set to something other than `master` | `""` |
+| `maxUnavailable` | The [maxUnavailable][] value for the pod disruption budget. By default this will prevent Kubernetes from having more than 1 unhealthy pod in the node group | `1` |
+| `nameOverride` | Overrides the `clusterName` when used in the naming of resources | `""` |
+| `networkHost` | Value for the `network.host OpenSearch setting` | `0.0.0.0` |
+| `networkPolicy.create` | Enable network policy creation for OpenSearch | `false`
+| `nodeAffinity` | Value for the [node affinity settings][] | `{}` |
+| `nodeGroup` | This is the name that will be used for each group of nodes in the cluster. The name will be `clusterName-nodeGroup-X` , `nameOverride-nodeGroup-X` if a `nameOverride` is specified, and `fullnameOverride-X` if a `fullnameOverride` is specified | `master` |
+| `nodeSelector` | Configurable [nodeSelector][] so that you can target specific nodes for your OpenSearch cluster | `{}` |
+| `persistence` | Enables a persistent volume for OpenSearch data. | see [values.yaml][] |
+| `persistence.enableInitChown` | Disable the `fsgroup-volume` initContainer that will update permissions on the persistent disk. | `true` |
+| `podAnnotations` | Configurable [annotations][] applied to all OpenSearch pods | `{}` |
+| `podManagementPolicy` | By default Kubernetes [deploys StatefulSets serially][]. This deploys them in parallel so that they can discover each other | `Parallel` |
+| `podSecurityContext` | Allows you to set the [securityContext][] for the pod | see [values.yaml][] |
+| `podSecurityPolicy` | Configuration for create a pod security policy with minimal permissions to run this Helm chart with `create: true`. Also can be used to reference an external pod security policy with `name: "externalPodSecurityPolicy"` | see [values.yaml][] |
+| `priorityClassName` | The name of the [PriorityClass][]. No default is supplied as the PriorityClass must be created first | `""` | |
+| `rbac` | Configuration for creating a role, role binding and ServiceAccount as part of this Helm chart with `create: true`. Also can be used to reference an external ServiceAccount with `serviceAccountName: "externalServiceAccountName"` | see [values.yaml][] |
+| `replicas` | Kubernetes replica count for the StatefulSet (i.e. how many pods) | `3` |
+| `resources` | Allows you to set the [resources][] for the StatefulSet | see [values.yaml][] |
+| `roles` | A list of the specific node [roles][] for the `nodeGroup` | see [values.yaml][] |
+| `singleNode` | If `discovery.type` in the opensearch configuration is set to `"single-node"`, this should be set to `true`. If `true`, replicas will be forced to `1`. | `false` |
+| `schedulerName` | Name of the [alternate scheduler][] | `""` |
+| `secretMounts` | Allows you easily mount a secret as a file inside the StatefulSet. Useful for mounting certificates and other secrets. See [values.yaml][] for an example | `[]` |
+| `securityConfig` | Configure the opensearch security plugin. There are multiple ways to inject configuration into the chart, see [values.yaml][] details. | By default an insecure demonstration configuration is set. This **must** be changed before going to production. |
+| `securityContext` | Allows you to set the [securityContext][] for the container | see [values.yaml][] |
+| `service.annotations` | [LoadBalancer annotations][] that Kubernetes will use for the service. This will configure load balancer if `service.type` is `LoadBalancer` | `{}` |
+| `service.headless.annotations` | Allow you to set annotations on the headless service | `{}` |
+| `service.externalTrafficPolicy` | Some cloud providers allow you to specify the [LoadBalancer externalTrafficPolicy][]. Kubernetes will use this to preserve the client source IP. This will configure load balancer if `service.type` is `LoadBalancer` | `""` |
+| `service.httpPortName` | The name of the http port within the service | `http` |
+| `service.labelsHeadless` | Labels to be added to headless service | `{}` |
+| `service.labels` | Labels to be added to non-headless service | `{}` |
+| `service.loadBalancerIP` | Some cloud providers allow you to specify the [loadBalancer][] IP. If the `loadBalancerIP` field is not specified, the IP is dynamically assigned. If you specify a `loadBalancerIP` but your cloud provider does not support the feature, it is ignored. | `""` |
+| `service.loadBalancerSourceRanges` | The IP ranges that are allowed to access | `[]` |
+| `service.nodePort` | Custom [nodePort][] port that can be set if you are using `service.type: nodePort` | `""` |
+| `service.transportPortName` | The name of the transport port within the service | `transport` |
+| `service.type` | OpenSearch [Service Types][] | `ClusterIP` |
+| `sidecarResources` | Allows you to set the [resources][] for the sidecar containers in the StatefulSet | {} |
+| `sysctlInit` | Allows you to enable the `sysctlInit` to set sysctl vm.max_map_count through privileged `initContainer`. | `enabled: false` |
+| `sysctlVmMaxMapCount` | Sets the [vm.max_map_count][] needed for OpenSearch | `262144` |
+| `terminationGracePeriod` | The [terminationGracePeriod][] in seconds used when trying to stop the pod | `120` |
+| `tolerations` | Configurable [tolerations][] | `[]` |
+| `topologySpreadConstraints` | Configuration for pod [topologySpreadConstraints][] | `[]` |
+| `transportPort` | The transport port that Kubernetes will use for the service. If you change this you will also need to set transport port configuration in `extraEnvs` | `9300` |
+| `updateStrategy` | The [updateStrategy][] for the StatefulSet. By default Kubernetes will wait for the cluster to be green after upgrading each pod. Setting this to `OnDelete` will allow you to manually delete each pod during upgrades | `RollingUpdate` |
+| `volumeClaimTemplate` | Configuration for the [volumeClaimTemplate for StatefulSets][]. You will want to adjust the storage (default `30Gi` ) and the `storageClassName` if you are using a different storage class | see [values.yaml][] |
+| `extraObjects` | Array of extra K8s manifests to deploy | list `[]` | |
+| `livenessProbe` | Configuration fields for the liveness [probe][] | see [exampleLiveness][] in `values.yaml`
+| `readinessProbe` | Configuration fields for the readiness [probe][] | see [exampleReadiness][] in `values.yaml`
+| `startupProbe` | Configuration fields for the startup [probe][] | see [exampleStartup][] in `values.yaml` |
+
+
+
+
+[anti-affinity]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
+
+[environment from variables]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables
+
+[values.yaml]:https://github.com/opensearch-project/helm-charts/blob/main/charts/opensearch/values.yaml
+
+[hostAliases]: https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/
+
+[image.pullPolicy]: https://kubernetes.io/docs/concepts/containers/images/#updating-images
+[imagePullSecrets]: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
+[ingress]: https://kubernetes.io/docs/concepts/services-networking/ingress/
+[resources]: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
+
+[labels]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
+
+[maxUnavailable]: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget
+
+[node affinity settings]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature
+
+[nodeSelector]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
+
+[annotations]: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
+
+[deploys statefulsets serially]: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies
+
+[securityContext]: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
+
+[priorityClass]: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
+
+[roles]: https://opensearch.org/docs/opensearch/cluster/
+
+[alternate scheduler]: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/#specify-schedulers-for-pods
+
+[loadBalancer annotations]: https://kubernetes.io/docs/concepts/services-networking/service/#ssl-support-on-aws
+[loadBalancer externalTrafficPolicy]: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip
+[loadBalancer]: https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer
+[maxUnavailable]: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget
+
+[nodePort]: https://kubernetes.io/docs/concepts/services-networking/service/#nodeport
+
+[nodeSelector]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
+
+[vm.max_map_count]: https://opensearch.org/docs/opensearch/install/important-settings/
+
+[terminationGracePeriod]: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods
+[tolerations]: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+
+[updateStrategy]: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
+[volumeClaimTemplate for statefulsets]: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-storage
+
+[service types]: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
+
+[topologySpreadConstraints]: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints
+
+[probe]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes
+
+[exampleStartup]: https://github.com/opensearch-project/helm-charts/blob/main/charts/opensearch/values.yaml#332
+[exampleLiveness]: https://github.com/opensearch-project/helm-charts/blob/main/charts/opensearch/values.yaml#340
+[exampleReadiness]: https://github.com/opensearch-project/helm-charts/blob/main/charts/opensearch/values.yaml#349
+
diff --git a/opensearch-bk/helm-charts/charts/opensearch/ci/ci-ingress-class-name-values.yaml b/opensearch-bk/helm-charts/charts/opensearch/ci/ci-ingress-class-name-values.yaml
new file mode 100644
index 00000000..2223f5bf
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/ci/ci-ingress-class-name-values.yaml
@@ -0,0 +1,428 @@
+---
+clusterName: "opensearch-cluster"
+nodeGroup: "master"
+
+# The service that non master groups will try to connect to when joining the cluster
+# This should be set to clusterName + "-" + nodeGroup for your master group
+masterService: "opensearch-cluster-master"
+
+# OpenSearch roles that will be applied to this nodeGroup
+# These will be set as environment variable "node.roles". E.g. node.roles=master,ingest,data,remote_cluster_client
+roles:
+ - master
+ - ingest
+ - data
+ - remote_cluster_client
+
+replicas: 1
+
+# if not set, falls back to parsing .Values.imageTag, then .Chart.appVersion.
+majorVersion: ""
+
+global:
+ # Set if you want to change the default docker registry, e.g. a private one.
+ dockerRegistry: ""
+
+# Allows you to add any config files in {{ .Values.opensearchHome }}/config
+opensearchHome: /usr/share/opensearch
+# such as opensearch.yml and log4j2.properties
+config:
+ # Values must be YAML literal style scalar / YAML multiline string.
+ # : |
+ #
+ # log4j2.properties: |
+ # status = error
+ #
+ # appender.console.type = Console
+ # appender.console.name = console
+ # appender.console.layout.type = PatternLayout
+ # appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker %m%n
+ #
+ # rootLogger.level = info
+ # rootLogger.appenderRef.console.ref = console
+ opensearch.yml: |
+ cluster.name: opensearch-cluster
+
+ # Bind to all interfaces because we don't know what IP address Docker will assign to us.
+ network.host: 0.0.0.0
+ transport.host: localhost
+ transport.tcp.port: 9300
+
+ # Setting network.host to a non-loopback address enables the annoying bootstrap checks. "Single-node" mode disables them again.
+ # discovery.type: single-node
+
+ # Start OpenSearch Security Demo Configuration
+ # WARNING: revise all the lines below before you go into production
+ plugins:
+ security:
+ ssl:
+ transport:
+ pemcert_filepath: esnode.pem
+ pemkey_filepath: esnode-key.pem
+ pemtrustedcas_filepath: root-ca.pem
+ enforce_hostname_verification: false
+ http:
+ enabled: true
+ pemcert_filepath: esnode.pem
+ pemkey_filepath: esnode-key.pem
+ pemtrustedcas_filepath: root-ca.pem
+ allow_unsafe_democertificates: true
+ allow_default_init_securityindex: true
+ authcz:
+ admin_dn:
+ - CN=kirk,OU=client,O=client,L=test,C=de
+ audit.type: internal_opensearch
+ enable_snapshot_restore_privilege: true
+ check_snapshot_restore_write_privileges: true
+ restapi:
+ roles_enabled: ["all_access", "security_rest_api_access"]
+ system_indices:
+ enabled: true
+ indices:
+ [
+ ".opendistro-alerting-config",
+ ".opendistro-alerting-alert*",
+ ".opendistro-anomaly-results*",
+ ".opendistro-anomaly-detector*",
+ ".opendistro-anomaly-checkpoints",
+ ".opendistro-anomaly-detection-state",
+ ".opendistro-reports-*",
+ ".opendistro-notifications-*",
+ ".opendistro-notebooks",
+ ".opendistro-asynchronous-search-response*",
+ ]
+ ######## End OpenSearch Security Demo Configuration ########
+ # log4j2.properties:
+
+# Extra environment variables to append to this nodeGroup
+# This will be appended to the current 'env:' key. You can use any of the kubernetes env
+# syntax here
+extraEnvs: []
+# - name: MY_ENVIRONMENT_VAR
+# value: the_value_goes_here
+
+# Allows you to load environment variables from kubernextes secret or config map
+envFrom: []
+# - secretRef:
+# name: env-secret
+# - configMapRef:
+# name: config-map
+
+# A list of secrets and their paths to mount inside the pod
+# This is useful for mounting certificates for security and for mounting
+# the X-Pack license
+secretMounts: []
+
+hostAliases: []
+# - ip: "127.0.0.1"
+# hostnames:
+# - "foo.local"
+# - "bar.local"
+
+image:
+ repository: "opensearchproject/opensearch"
+ # override image tag, which is .Chart.AppVersion by default
+ tag: ""
+ pullPolicy: "IfNotPresent"
+
+podAnnotations: {}
+ # iam.amazonaws.com/role: es-cluster
+
+# additionals labels
+labels: {}
+
+opensearchJavaOpts: "-Xmx512M -Xms512M"
+
+resources:
+ requests:
+ cpu: "1000m"
+ memory: "100Mi"
+
+initResources: {}
+ # limits:
+ # cpu: "25m"
+ # # memory: "128Mi"
+ # requests:
+ # cpu: "25m"
+ # memory: "128Mi"
+
+sidecarResources: {}
+ # limits:
+ # cpu: "25m"
+ # # memory: "128Mi"
+ # requests:
+ # cpu: "25m"
+ # memory: "128Mi"
+
+networkHost: "0.0.0.0"
+
+rbac:
+ create: false
+ serviceAccountAnnotations: {}
+ serviceAccountName: ""
+
+podSecurityPolicy:
+ create: false
+ name: ""
+ spec:
+ privileged: true
+ fsGroup:
+ rule: RunAsAny
+ runAsUser:
+ rule: RunAsAny
+ seLinux:
+ rule: RunAsAny
+ supplementalGroups:
+ rule: RunAsAny
+ volumes:
+ - secret
+ - configMap
+ - persistentVolumeClaim
+ - emptyDir
+
+persistence:
+ enabled: true
+ # Set to false to disable the `fsgroup-volume` initContainer that will update permissions on the persistent disk.
+ enableInitChown: true
+ # override image, which is busybox by default
+ # image: busybox
+ # override image tag, which is latest by default
+ # imageTag:
+ labels:
+ # Add default labels for the volumeClaimTemplate of the StatefulSet
+ enabled: false
+ # OpenSearch Persistent Volume Storage Class
+ # If defined, storageClassName:
+ # If set to "-", storageClassName: "", which disables dynamic provisioning
+ # If undefined (the default) or set to null, no storageClassName spec is
+ # set, choosing the default provisioner. (gp2 on AWS, standard on
+ # GKE, AWS & OpenStack)
+ #
+ # storageClass: "-"
+ accessModes:
+ - ReadWriteOnce
+ size: 8Gi
+ annotations: {}
+
+extraVolumes: []
+ # - name: extras
+ # emptyDir: {}
+
+extraVolumeMounts: []
+ # - name: extras
+ # mountPath: /usr/share/extras
+ # readOnly: true
+
+extraContainers: []
+ # - name: do-something
+ # image: busybox
+ # command: ['do', 'something']
+
+extraInitContainers: []
+ # - name: do-somethings
+ # image: busybox
+ # command: ['do', 'something']
+
+# This is the PriorityClass settings as defined in
+# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
+priorityClassName: ""
+
+# By default this will make sure two pods don't end up on the same node
+# Changing this to a region would allow you to spread pods across regions
+antiAffinityTopologyKey: "kubernetes.io/hostname"
+
+# Hard means that by default pods will only be scheduled if there are enough nodes for them
+# and that they will never end up on the same node. Setting this to soft will do this "best effort"
+antiAffinity: "soft"
+
+# This is the node affinity settings as defined in
+# https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature
+nodeAffinity: {}
+
+# The default is to deploy all pods serially. By setting this to parallel all pods are started at
+# the same time when bootstrapping the cluster
+podManagementPolicy: "Parallel"
+
+# The environment variables injected by service links are not used, but can lead to slow OpenSearch boot times when
+# there are many services in the current namespace.
+# If you experience slow pod startups you probably want to set this to `false`.
+enableServiceLinks: true
+
+protocol: https
+httpPort: 9200
+transportPort: 9300
+
+service:
+ labels: {}
+ labelsHeadless: {}
+ headless:
+ annotations: {}
+ type: ClusterIP
+ nodePort: ""
+ annotations: {}
+ httpPortName: http
+ transportPortName: transport
+ loadBalancerIP: ""
+ loadBalancerSourceRanges: []
+ externalTrafficPolicy: ""
+
+updateStrategy: RollingUpdate
+
+# This is the max unavailable setting for the pod disruption budget
+# The default value of 1 will make sure that kubernetes won't allow more than 1
+# of your pods to be unavailable during maintenance
+maxUnavailable: 1
+
+podSecurityContext:
+ fsGroup: 1000
+ runAsUser: 1000
+
+securityContext:
+ capabilities:
+ drop:
+ - ALL
+ # readOnlyRootFilesystem: true
+ runAsNonRoot: true
+ runAsUser: 1000
+
+securityConfig:
+ enabled: true
+ path: "/usr/share/opensearch/plugins/opensearch-security/securityconfig"
+ actionGroupsSecret:
+ configSecret:
+ internalUsersSecret:
+ rolesSecret:
+ rolesMappingSecret:
+ tenantsSecret:
+ # The following option simplifies securityConfig by using a single secret and
+ # specifying the config files as keys in the secret instead of creating
+ # different secrets for for each config file.
+ # Note that this is an alternative to the individual secret configuration
+ # above and shouldn't be used if the above secrets are used.
+ config:
+ # There are multiple ways to define the configuration here:
+ # * If you define anything under data, the chart will automatically create
+ # a secret and mount it.
+ # * If you define securityConfigSecret, the chart will assume this secret is
+ # created externally and mount it.
+ # * It is an error to define both data and securityConfigSecret.
+ securityConfigSecret: ""
+ data: {}
+ # config.yml: |-
+ # internal_users.yml: |-
+ # roles.yml: |-
+ # roles_mapping.yml: |-
+ # action_groups.yml: |-
+ # tenants.yml: |-
+
+# How long to wait for opensearch to stop gracefully
+terminationGracePeriod: 120
+
+sysctlVmMaxMapCount: 262144
+
+startupProbe:
+ tcpSocket:
+ port: 9200
+ initialDelaySeconds: 5
+ periodSeconds: 10
+ timeoutSeconds: 3
+ failureThreshold: 30
+
+readinessProbe:
+ failureThreshold: 3
+ initialDelaySeconds: 900
+ periodSeconds: 10
+ successThreshold: 3
+ timeoutSeconds: 2
+
+## Use an alternate scheduler.
+## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
+##
+schedulerName: ""
+
+imagePullSecrets: []
+nodeSelector: {}
+tolerations: []
+
+# Enabling this will publically expose your OpenSearch instance.
+# Only enable this if you have security enabled on your cluster
+ingress:
+ enabled: true
+
+ # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
+ # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
+ ingressClassName: nginx
+
+ annotations: {}
+ # kubernetes.io/ingress.class: nginx
+ # kubernetes.io/tls-acme: "true"
+ path: /
+ hosts:
+ - chart-example.local
+ tls: []
+ # - secretName: chart-example-tls
+ # hosts:
+ # - chart-example.local
+
+nameOverride: ""
+fullnameOverride: ""
+
+masterTerminationFix: false
+
+lifecycle: {}
+ # preStop:
+ # exec:
+ # command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
+ # postStart:
+ # exec:
+ # command:
+ # - bash
+ # - -c
+ # - |
+ # #!/bin/bash
+ # # Add a template to adjust number of shards/replicas1
+ # TEMPLATE_NAME=my_template
+ # INDEX_PATTERN="logstash-*"
+ # SHARD_COUNT=8
+ # REPLICA_COUNT=1
+ # ES_URL=http://localhost:9200
+ # while [[ "$(curl -s -o /dev/null -w '%{http_code}\n' $ES_URL)" != "200" ]]; do sleep 1; done
+ # curl -XPUT "$ES_URL/_template/$TEMPLATE_NAME" -H 'Content-Type: application/json' -d'{"index_patterns":['\""$INDEX_PATTERN"\"'],"settings":{"number_of_shards":'$SHARD_COUNT',"number_of_replicas":'$REPLICA_COUNT'}}'
+
+keystore: []
+
+networkPolicy:
+ ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now.
+ ## In order for a Pod to access OpenSearch, it needs to have the following label:
+ ## {{ template "uname" . }}-client: "true"
+ ## Example for default configuration to access HTTP port:
+ ## opensearch-master-http-client: "true"
+ ## Example for default configuration to access transport port:
+ ## opensearch-master-transport-client: "true"
+
+ http:
+ enabled: false
+
+# Deprecated
+# please use the above podSecurityContext.fsGroup instead
+fsGroup: ""
+
+## Set optimal sysctl's through securityContext. This requires privilege. Can be disabled if
+## the system has already been preconfigured. (Ex: https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html)
+## Also see: https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/
+sysctl:
+ enabled: false
+
+## Set optimal sysctl's through privileged initContainer.
+sysctlInit:
+ enabled: true
+ # override image, which is busybox by default
+ # image: busybox
+ # override image tag, which is latest by default
+ # imageTag:
+
+## Enable to add 3rd Party / Custom plugins not offered in the default OpenSearch image.
+plugins:
+ enabled: false
+ installList: []
+ # - example-fake-plugin
diff --git a/opensearch-bk/helm-charts/charts/opensearch/ci/ci-rbac-enabled-values.yaml b/opensearch-bk/helm-charts/charts/opensearch/ci/ci-rbac-enabled-values.yaml
new file mode 100644
index 00000000..42ec6231
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/ci/ci-rbac-enabled-values.yaml
@@ -0,0 +1,428 @@
+---
+clusterName: "opensearch-cluster"
+nodeGroup: "master"
+
+# The service that non master groups will try to connect to when joining the cluster
+# This should be set to clusterName + "-" + nodeGroup for your master group
+masterService: "opensearch-cluster-master"
+
+# OpenSearch roles that will be applied to this nodeGroup
+# These will be set as environment variable "node.roles". E.g. node.roles=master,ingest,data,remote_cluster_client
+roles:
+ - master
+ - ingest
+ - data
+ - remote_cluster_client
+
+replicas: 1
+
+# if not set, falls back to parsing .Values.imageTag, then .Chart.appVersion.
+majorVersion: ""
+
+global:
+ # Set if you want to change the default docker registry, e.g. a private one.
+ dockerRegistry: ""
+
+# Allows you to add any config files in {{ .Values.opensearchHome }}/config
+opensearchHome: /usr/share/opensearch
+# such as opensearch.yml and log4j2.properties
+config:
+ # Values must be YAML literal style scalar / YAML multiline string.
+ # : |
+ #
+ # log4j2.properties: |
+ # status = error
+ #
+ # appender.console.type = Console
+ # appender.console.name = console
+ # appender.console.layout.type = PatternLayout
+ # appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker %m%n
+ #
+ # rootLogger.level = info
+ # rootLogger.appenderRef.console.ref = console
+ opensearch.yml: |
+ cluster.name: opensearch-cluster
+
+ # Bind to all interfaces because we don't know what IP address Docker will assign to us.
+ network.host: 0.0.0.0
+ transport.host: localhost
+ transport.tcp.port: 9300
+
+ # Setting network.host to a non-loopback address enables the annoying bootstrap checks. "Single-node" mode disables them again.
+ # discovery.type: single-node
+
+ # Start OpenSearch Security Demo Configuration
+ # WARNING: revise all the lines below before you go into production
+ plugins:
+ security:
+ ssl:
+ transport:
+ pemcert_filepath: esnode.pem
+ pemkey_filepath: esnode-key.pem
+ pemtrustedcas_filepath: root-ca.pem
+ enforce_hostname_verification: false
+ http:
+ enabled: true
+ pemcert_filepath: esnode.pem
+ pemkey_filepath: esnode-key.pem
+ pemtrustedcas_filepath: root-ca.pem
+ allow_unsafe_democertificates: true
+ allow_default_init_securityindex: true
+ authcz:
+ admin_dn:
+ - CN=kirk,OU=client,O=client,L=test,C=de
+ audit.type: internal_opensearch
+ enable_snapshot_restore_privilege: true
+ check_snapshot_restore_write_privileges: true
+ restapi:
+ roles_enabled: ["all_access", "security_rest_api_access"]
+ system_indices:
+ enabled: true
+ indices:
+ [
+ ".opendistro-alerting-config",
+ ".opendistro-alerting-alert*",
+ ".opendistro-anomaly-results*",
+ ".opendistro-anomaly-detector*",
+ ".opendistro-anomaly-checkpoints",
+ ".opendistro-anomaly-detection-state",
+ ".opendistro-reports-*",
+ ".opendistro-notifications-*",
+ ".opendistro-notebooks",
+ ".opendistro-asynchronous-search-response*",
+ ]
+ ######## End OpenSearch Security Demo Configuration ########
+ # log4j2.properties:
+
+# Extra environment variables to append to this nodeGroup
+# This will be appended to the current 'env:' key. You can use any of the kubernetes env
+# syntax here
+extraEnvs: []
+# - name: MY_ENVIRONMENT_VAR
+# value: the_value_goes_here
+
+# Allows you to load environment variables from kubernextes secret or config map
+envFrom: []
+# - secretRef:
+# name: env-secret
+# - configMapRef:
+# name: config-map
+
+# A list of secrets and their paths to mount inside the pod
+# This is useful for mounting certificates for security and for mounting
+# the X-Pack license
+secretMounts: []
+
+hostAliases: []
+# - ip: "127.0.0.1"
+# hostnames:
+# - "foo.local"
+# - "bar.local"
+
+image:
+ repository: "opensearchproject/opensearch"
+ # override image tag, which is .Chart.AppVersion by default
+ tag: ""
+ pullPolicy: "IfNotPresent"
+
+podAnnotations: {}
+ # iam.amazonaws.com/role: es-cluster
+
+# additionals labels
+labels: {}
+
+opensearchJavaOpts: "-Xmx512M -Xms512M"
+
+resources:
+ requests:
+ cpu: "1000m"
+ memory: "100Mi"
+
+initResources: {}
+ # limits:
+ # cpu: "25m"
+ # # memory: "128Mi"
+ # requests:
+ # cpu: "25m"
+ # memory: "128Mi"
+
+sidecarResources: {}
+ # limits:
+ # cpu: "25m"
+ # # memory: "128Mi"
+ # requests:
+ # cpu: "25m"
+ # memory: "128Mi"
+
+networkHost: "0.0.0.0"
+
+rbac:
+ create: true
+ serviceAccountAnnotations: {}
+ serviceAccountName: ""
+
+podSecurityPolicy:
+ create: false
+ name: ""
+ spec:
+ privileged: true
+ fsGroup:
+ rule: RunAsAny
+ runAsUser:
+ rule: RunAsAny
+ seLinux:
+ rule: RunAsAny
+ supplementalGroups:
+ rule: RunAsAny
+ volumes:
+ - secret
+ - configMap
+ - persistentVolumeClaim
+ - emptyDir
+
+persistence:
+ enabled: true
+ # Set to false to disable the `fsgroup-volume` initContainer that will update permissions on the persistent disk.
+ enableInitChown: true
+ # override image, which is busybox by default
+ # image: busybox
+ # override image tag, which is latest by default
+ # imageTag:
+ labels:
+ # Add default labels for the volumeClaimTemplate of the StatefulSet
+ enabled: false
+ # OpenSearch Persistent Volume Storage Class
+ # If defined, storageClassName:
+ # If set to "-", storageClassName: "", which disables dynamic provisioning
+ # If undefined (the default) or set to null, no storageClassName spec is
+ # set, choosing the default provisioner. (gp2 on AWS, standard on
+ # GKE, AWS & OpenStack)
+ #
+ # storageClass: "-"
+ accessModes:
+ - ReadWriteOnce
+ size: 8Gi
+ annotations: {}
+
+extraVolumes: []
+ # - name: extras
+ # emptyDir: {}
+
+extraVolumeMounts: []
+ # - name: extras
+ # mountPath: /usr/share/extras
+ # readOnly: true
+
+extraContainers: []
+ # - name: do-something
+ # image: busybox
+ # command: ['do', 'something']
+
+extraInitContainers: []
+ # - name: do-somethings
+ # image: busybox
+ # command: ['do', 'something']
+
+# This is the PriorityClass settings as defined in
+# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
+priorityClassName: ""
+
+# By default this will make sure two pods don't end up on the same node
+# Changing this to a region would allow you to spread pods across regions
+antiAffinityTopologyKey: "kubernetes.io/hostname"
+
+# Hard means that by default pods will only be scheduled if there are enough nodes for them
+# and that they will never end up on the same node. Setting this to soft will do this "best effort"
+antiAffinity: "soft"
+
+# This is the node affinity settings as defined in
+# https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature
+nodeAffinity: {}
+
+# The default is to deploy all pods serially. By setting this to parallel all pods are started at
+# the same time when bootstrapping the cluster
+podManagementPolicy: "Parallel"
+
+# The environment variables injected by service links are not used, but can lead to slow OpenSearch boot times when
+# there are many services in the current namespace.
+# If you experience slow pod startups you probably want to set this to `false`.
+enableServiceLinks: true
+
+protocol: https
+httpPort: 9200
+transportPort: 9300
+
+service:
+ labels: {}
+ labelsHeadless: {}
+ headless:
+ annotations: {}
+ type: ClusterIP
+ nodePort: ""
+ annotations: {}
+ httpPortName: http
+ transportPortName: transport
+ loadBalancerIP: ""
+ loadBalancerSourceRanges: []
+ externalTrafficPolicy: ""
+
+updateStrategy: RollingUpdate
+
+# This is the max unavailable setting for the pod disruption budget
+# The default value of 1 will make sure that kubernetes won't allow more than 1
+# of your pods to be unavailable during maintenance
+maxUnavailable: 1
+
+podSecurityContext:
+ fsGroup: 1000
+ runAsUser: 1000
+
+securityContext:
+ capabilities:
+ drop:
+ - ALL
+ # readOnlyRootFilesystem: true
+ runAsNonRoot: true
+ runAsUser: 1000
+
+securityConfig:
+ enabled: true
+ path: "/usr/share/opensearch/plugins/opensearch-security/securityconfig"
+ actionGroupsSecret:
+ configSecret:
+ internalUsersSecret:
+ rolesSecret:
+ rolesMappingSecret:
+ tenantsSecret:
+ # The following option simplifies securityConfig by using a single secret and
+ # specifying the config files as keys in the secret instead of creating
+ # different secrets for for each config file.
+ # Note that this is an alternative to the individual secret configuration
+ # above and shouldn't be used if the above secrets are used.
+ config:
+ # There are multiple ways to define the configuration here:
+ # * If you define anything under data, the chart will automatically create
+ # a secret and mount it.
+ # * If you define securityConfigSecret, the chart will assume this secret is
+ # created externally and mount it.
+ # * It is an error to define both data and securityConfigSecret.
+ securityConfigSecret: ""
+ data: {}
+ # config.yml: |-
+ # internal_users.yml: |-
+ # roles.yml: |-
+ # roles_mapping.yml: |-
+ # action_groups.yml: |-
+ # tenants.yml: |-
+
+# How long to wait for opensearch to stop gracefully
+terminationGracePeriod: 120
+
+sysctlVmMaxMapCount: 262144
+
+startupProbe:
+ tcpSocket:
+ port: 9200
+ initialDelaySeconds: 5
+ periodSeconds: 10
+ timeoutSeconds: 3
+ failureThreshold: 30
+
+readinessProbe:
+ failureThreshold: 3
+ initialDelaySeconds: 900
+ periodSeconds: 10
+ successThreshold: 3
+ timeoutSeconds: 2
+
+## Use an alternate scheduler.
+## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
+##
+schedulerName: ""
+
+imagePullSecrets: []
+nodeSelector: {}
+tolerations: []
+
+# Enabling this will publically expose your OpenSearch instance.
+# Only enable this if you have security enabled on your cluster
+ingress:
+ enabled: false
+
+ # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
+ # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
+ ingressClassName: nginx
+
+ annotations: {}
+ # kubernetes.io/ingress.class: nginx
+ # kubernetes.io/tls-acme: "true"
+ path: /
+ hosts:
+ - chart-example.local
+ tls: []
+ # - secretName: chart-example-tls
+ # hosts:
+ # - chart-example.local
+
+nameOverride: ""
+fullnameOverride: ""
+
+masterTerminationFix: false
+
+lifecycle: {}
+ # preStop:
+ # exec:
+ # command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
+ # postStart:
+ # exec:
+ # command:
+ # - bash
+ # - -c
+ # - |
+ # #!/bin/bash
+ # # Add a template to adjust number of shards/replicas1
+ # TEMPLATE_NAME=my_template
+ # INDEX_PATTERN="logstash-*"
+ # SHARD_COUNT=8
+ # REPLICA_COUNT=1
+ # ES_URL=http://localhost:9200
+ # while [[ "$(curl -s -o /dev/null -w '%{http_code}\n' $ES_URL)" != "200" ]]; do sleep 1; done
+ # curl -XPUT "$ES_URL/_template/$TEMPLATE_NAME" -H 'Content-Type: application/json' -d'{"index_patterns":['\""$INDEX_PATTERN"\"'],"settings":{"number_of_shards":'$SHARD_COUNT',"number_of_replicas":'$REPLICA_COUNT'}}'
+
+keystore: []
+
+networkPolicy:
+ ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now.
+ ## In order for a Pod to access OpenSearch, it needs to have the following label:
+ ## {{ template "uname" . }}-client: "true"
+ ## Example for default configuration to access HTTP port:
+ ## opensearch-master-http-client: "true"
+ ## Example for default configuration to access transport port:
+ ## opensearch-master-transport-client: "true"
+
+ http:
+ enabled: false
+
+# Deprecated
+# please use the above podSecurityContext.fsGroup instead
+fsGroup: ""
+
+## Set optimal sysctl's through securityContext. This requires privilege. Can be disabled if
+## the system has already been preconfigured. (Ex: https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html)
+## Also see: https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/
+sysctl:
+ enabled: false
+
+## Set optimal sysctl's through privileged initContainer.
+sysctlInit:
+ enabled: false
+ # override image, which is busybox by default
+ # image: busybox
+ # override image tag, which is latest by default
+ # imageTag:
+
+## Enable to add 3rd Party / Custom plugins not offered in the default OpenSearch image.
+plugins:
+ enabled: false
+ installList: []
+ # - example-fake-plugin
diff --git a/opensearch-bk/helm-charts/charts/opensearch/ci/ci-values.yaml b/opensearch-bk/helm-charts/charts/opensearch/ci/ci-values.yaml
new file mode 100644
index 00000000..c63eab66
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/ci/ci-values.yaml
@@ -0,0 +1,415 @@
+---
+clusterName: "opensearch-cluster"
+nodeGroup: "master"
+
+# The service that non master groups will try to connect to when joining the cluster
+# This should be set to clusterName + "-" + nodeGroup for your master group
+masterService: "opensearch-cluster-master"
+
+# OpenSearch roles that will be applied to this nodeGroup
+# These will be set as environment variable "node.roles". E.g. node.roles=master,ingest,data,remote_cluster_client
+roles:
+ - master
+ - ingest
+ - data
+ - remote_cluster_client
+
+replicas: 1
+
+# if not set, falls back to parsing .Values.imageTag, then .Chart.appVersion.
+majorVersion: ""
+
+global:
+ # Set if you want to change the default docker registry, e.g. a private one.
+ dockerRegistry: ""
+
+# Allows you to add any config files in {{ .Values.opensearchHome }}/config
+opensearchHome: /usr/share/opensearch
+# such as opensearch.yml and log4j2.properties
+config:
+ # Values must be YAML literal style scalar / YAML multiline string.
+ # : |
+ #
+ # log4j2.properties: |
+ # status = error
+ #
+ # appender.console.type = Console
+ # appender.console.name = console
+ # appender.console.layout.type = PatternLayout
+ # appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker %m%n
+ #
+ # rootLogger.level = info
+ # rootLogger.appenderRef.console.ref = console
+ opensearch.yml: |
+ cluster.name: opensearch-cluster
+
+ # Bind to all interfaces because we don't know what IP address Docker will assign to us.
+ network.host: 0.0.0.0
+ transport.host: localhost
+ transport.tcp.port: 9300
+
+ # Setting network.host to a non-loopback address enables the annoying bootstrap checks. "Single-node" mode disables them again.
+ # discovery.type: single-node
+
+ # Start OpenSearch Security Demo Configuration
+ # WARNING: revise all the lines below before you go into production
+ plugins:
+ security:
+ ssl:
+ transport:
+ pemcert_filepath: esnode.pem
+ pemkey_filepath: esnode-key.pem
+ pemtrustedcas_filepath: root-ca.pem
+ enforce_hostname_verification: false
+ http:
+ enabled: true
+ pemcert_filepath: esnode.pem
+ pemkey_filepath: esnode-key.pem
+ pemtrustedcas_filepath: root-ca.pem
+ allow_unsafe_democertificates: true
+ allow_default_init_securityindex: true
+ authcz:
+ admin_dn:
+ - CN=kirk,OU=client,O=client,L=test,C=de
+ audit.type: internal_opensearch
+ enable_snapshot_restore_privilege: true
+ check_snapshot_restore_write_privileges: true
+ restapi:
+ roles_enabled: ["all_access", "security_rest_api_access"]
+ system_indices:
+ enabled: true
+ indices:
+ [
+ ".opendistro-alerting-config",
+ ".opendistro-alerting-alert*",
+ ".opendistro-anomaly-results*",
+ ".opendistro-anomaly-detector*",
+ ".opendistro-anomaly-checkpoints",
+ ".opendistro-anomaly-detection-state",
+ ".opendistro-reports-*",
+ ".opendistro-notifications-*",
+ ".opendistro-notebooks",
+ ".opendistro-asynchronous-search-response*",
+ ]
+ ######## End OpenSearch Security Demo Configuration ########
+ # log4j2.properties:
+
+# Extra environment variables to append to this nodeGroup
+# This will be appended to the current 'env:' key. You can use any of the kubernetes env
+# syntax here
+extraEnvs: []
+# - name: MY_ENVIRONMENT_VAR
+# value: the_value_goes_here
+
+# Allows you to load environment variables from kubernextes secret or config map
+envFrom: []
+# - secretRef:
+# name: env-secret
+# - configMapRef:
+# name: config-map
+
+# A list of secrets and their paths to mount inside the pod
+# This is useful for mounting certificates for security and for mounting
+# the X-Pack license
+secretMounts: []
+
+hostAliases: []
+# - ip: "127.0.0.1"
+# hostnames:
+# - "foo.local"
+# - "bar.local"
+
+
+image:
+ repository: "opensearchproject/opensearch"
+ # override image tag, which is .Chart.AppVersion by default
+ tag: ""
+ pullPolicy: "IfNotPresent"
+
+
+podAnnotations: {}
+ # iam.amazonaws.com/role: es-cluster
+
+# additionals labels
+labels: {}
+
+opensearchJavaOpts: "-Xmx512M -Xms512M"
+
+resources:
+ requests:
+ cpu: "1000m"
+ memory: "100Mi"
+
+initResources: {}
+ # limits:
+ # cpu: "25m"
+ # # memory: "128Mi"
+ # requests:
+ # cpu: "25m"
+ # memory: "128Mi"
+
+sidecarResources: {}
+ # limits:
+ # cpu: "25m"
+ # # memory: "128Mi"
+ # requests:
+ # cpu: "25m"
+ # memory: "128Mi"
+
+networkHost: "0.0.0.0"
+
+rbac:
+ create: false
+ serviceAccountAnnotations: {}
+ serviceAccountName: ""
+
+podSecurityPolicy:
+ create: false
+ name: ""
+ spec:
+ privileged: true
+ fsGroup:
+ rule: RunAsAny
+ runAsUser:
+ rule: RunAsAny
+ seLinux:
+ rule: RunAsAny
+ supplementalGroups:
+ rule: RunAsAny
+ volumes:
+ - secret
+ - configMap
+ - persistentVolumeClaim
+ - emptyDir
+
+persistence:
+ enabled: true
+ # Set to false to disable the `fsgroup-volume` initContainer that will update permissions on the persistent disk.
+ enableInitChown: true
+ # override image, which is busybox by default
+ # image: busybox
+ # override image tag, which is latest by default
+ # imageTag:
+ labels:
+ # Add default labels for the volumeClaimTemplate of the StatefulSet
+ enabled: false
+ # OpenSearch Persistent Volume Storage Class
+ # If defined, storageClassName:
+ # If set to "-", storageClassName: "", which disables dynamic provisioning
+ # If undefined (the default) or set to null, no storageClassName spec is
+ # set, choosing the default provisioner. (gp2 on AWS, standard on
+ # GKE, AWS & OpenStack)
+ #
+ # storageClass: "-"
+ accessModes:
+ - ReadWriteOnce
+ size: 8Gi
+ annotations: {}
+
+extraVolumes: []
+ # - name: extras
+ # emptyDir: {}
+
+extraVolumeMounts: []
+ # - name: extras
+ # mountPath: /usr/share/extras
+ # readOnly: true
+
+extraContainers: []
+ # - name: do-something
+ # image: busybox
+ # command: ['do', 'something']
+
+extraInitContainers: []
+ # - name: do-somethings
+ # image: busybox
+ # command: ['do', 'something']
+
+# This is the PriorityClass settings as defined in
+# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
+priorityClassName: ""
+
+# By default this will make sure two pods don't end up on the same node
+# Changing this to a region would allow you to spread pods across regions
+antiAffinityTopologyKey: "kubernetes.io/hostname"
+
+# Hard means that by default pods will only be scheduled if there are enough nodes for them
+# and that they will never end up on the same node. Setting this to soft will do this "best effort"
+antiAffinity: "soft"
+
+# This is the node affinity settings as defined in
+# https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature
+nodeAffinity: {}
+
+# The default is to deploy all pods serially. By setting this to parallel all pods are started at
+# the same time when bootstrapping the cluster
+podManagementPolicy: "Parallel"
+
+# The environment variables injected by service links are not used, but can lead to slow OpenSearch boot times when
+# there are many services in the current namespace.
+# If you experience slow pod startups you probably want to set this to `false`.
+enableServiceLinks: true
+
+protocol: https
+httpPort: 9200
+transportPort: 9300
+
+service:
+ labels: {}
+ labelsHeadless: {}
+ headless:
+ annotations: {}
+ type: ClusterIP
+ nodePort: ""
+ annotations: {}
+ httpPortName: http
+ transportPortName: transport
+ loadBalancerIP: ""
+ loadBalancerSourceRanges: []
+ externalTrafficPolicy: ""
+
+updateStrategy: RollingUpdate
+
+# This is the max unavailable setting for the pod disruption budget
+# The default value of 1 will make sure that kubernetes won't allow more than 1
+# of your pods to be unavailable during maintenance
+maxUnavailable: 1
+
+podSecurityContext:
+ fsGroup: 1000
+ runAsUser: 1000
+
+securityContext:
+ capabilities:
+ drop:
+ - ALL
+ # readOnlyRootFilesystem: true
+ runAsNonRoot: true
+ runAsUser: 1000
+
+securityConfig:
+ enabled: true
+ path: "/usr/share/opensearch/plugins/opensearch-security/securityconfig"
+ actionGroupsSecret:
+ configSecret:
+ internalUsersSecret:
+ rolesSecret:
+ rolesMappingSecret:
+ tenantsSecret:
+ # The following option simplifies securityConfig by using a single secret and
+ # specifying the config files as keys in the secret instead of creating
+ # different secrets for for each config file.
+ # Note that this is an alternative to the individual secret configuration
+ # above and shouldn't be used if the above secrets are used.
+ config:
+ # There are multiple ways to define the configuration here:
+ # * If you define anything under data, the chart will automatically create
+ # a secret and mount it.
+ # * If you define securityConfigSecret, the chart will assume this secret is
+ # created externally and mount it.
+ # * It is an error to define both data and securityConfigSecret.
+ securityConfigSecret: ""
+ data: {}
+ # config.yml: |-
+ # internal_users.yml: |-
+ # roles.yml: |-
+ # roles_mapping.yml: |-
+ # action_groups.yml: |-
+ # tenants.yml: |-
+
+# How long to wait for opensearch to stop gracefully
+terminationGracePeriod: 120
+
+sysctlVmMaxMapCount: 262144
+
+## Use an alternate scheduler.
+## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
+##
+schedulerName: ""
+
+imagePullSecrets: []
+nodeSelector: {}
+tolerations: []
+
+# Enabling this will publically expose your OpenSearch instance.
+# Only enable this if you have security enabled on your cluster
+ingress:
+ enabled: false
+
+ # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
+ # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
+ ingressClassName: nginx
+
+ annotations: {}
+ # kubernetes.io/ingress.class: nginx
+ # kubernetes.io/tls-acme: "true"
+ path: /
+ hosts:
+ - chart-example.local
+ tls: []
+ # - secretName: chart-example-tls
+ # hosts:
+ # - chart-example.local
+
+nameOverride: ""
+fullnameOverride: ""
+
+masterTerminationFix: false
+
+lifecycle: {}
+ # preStop:
+ # exec:
+ # command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
+ # postStart:
+ # exec:
+ # command:
+ # - bash
+ # - -c
+ # - |
+ # #!/bin/bash
+ # # Add a template to adjust number of shards/replicas1
+ # TEMPLATE_NAME=my_template
+ # INDEX_PATTERN="logstash-*"
+ # SHARD_COUNT=8
+ # REPLICA_COUNT=1
+ # ES_URL=http://localhost:9200
+ # while [[ "$(curl -s -o /dev/null -w '%{http_code}\n' $ES_URL)" != "200" ]]; do sleep 1; done
+ # curl -XPUT "$ES_URL/_template/$TEMPLATE_NAME" -H 'Content-Type: application/json' -d'{"index_patterns":['\""$INDEX_PATTERN"\"'],"settings":{"number_of_shards":'$SHARD_COUNT',"number_of_replicas":'$REPLICA_COUNT'}}'
+
+keystore: []
+
+networkPolicy:
+ ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now.
+ ## In order for a Pod to access OpenSearch, it needs to have the following label:
+ ## {{ template "uname" . }}-client: "true"
+ ## Example for default configuration to access HTTP port:
+ ## opensearch-master-http-client: "true"
+ ## Example for default configuration to access transport port:
+ ## opensearch-master-transport-client: "true"
+
+ http:
+ enabled: false
+
+# Deprecated
+# please use the above podSecurityContext.fsGroup instead
+fsGroup: ""
+
+## Set optimal sysctl's through securityContext. This requires privilege. Can be disabled if
+## the system has already been preconfigured. (Ex: https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html)
+## Also see: https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/
+sysctl:
+ enabled: false
+
+## Set optimal sysctl's through privileged initContainer.
+sysctlInit:
+ enabled: false
+ # override image, which is busybox by default
+ # image: busybox
+ # override image tag, which is latest by default
+ # imageTag:
+
+## Enable to add 3rd Party / Custom plugins not offered in the default OpenSearch image.
+plugins:
+ enabled: false
+ installList: []
+ # - example-fake-plugin
diff --git a/opensearch-bk/helm-charts/charts/opensearch/pv.yaml b/opensearch-bk/helm-charts/charts/opensearch/pv.yaml
new file mode 100644
index 00000000..d79910ae
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/pv.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: opensearch-cluster-master-pv-master
+spec:
+ accessModes:
+ - ReadWriteOnce
+ capacity:
+ storage: 8Gi
+ claimRef:
+ apiVersion: v1
+ kind: PersistentVolumeClaim
+ name: opensearch-cluster-master-opensearch-cluster-master-0
+ namespace: opensearch
+ hostPath:
+ path: /tmp/mypvsc
+ type: DirectoryOrCreate
+ persistentVolumeReclaimPolicy: Delete
+ storageClassName: local-path
+ volumeMode: Filesystem
\ No newline at end of file
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/NOTES.txt b/opensearch-bk/helm-charts/charts/opensearch/templates/NOTES.txt
new file mode 100644
index 00000000..110e677b
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/NOTES.txt
@@ -0,0 +1,2 @@
+Watch all cluster members come up.
+ $ kubectl get pods --namespace={{ .Release.Namespace }} -l app.kubernetes.io/component={{ template "opensearch.uname" . }} -w
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/_helpers.tpl b/opensearch-bk/helm-charts/charts/opensearch/templates/_helpers.tpl
new file mode 100644
index 00000000..f7dc47d0
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/_helpers.tpl
@@ -0,0 +1,144 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "opensearch.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 "opensearch.fullname" -}}
+{{- if contains .Chart.Name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "opensearch.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "opensearch.labels" -}}
+helm.sh/chart: {{ include "opensearch.chart" . }}
+{{ include "opensearch.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+app.kubernetes.io/component: {{ include "opensearch.uname" . }}
+{{- with .Values.labels }}
+{{ toYaml . }}
+{{- end }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "opensearch.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "opensearch.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{- define "opensearch.uname" -}}
+{{- if empty .Values.fullnameOverride -}}
+{{- if empty .Values.nameOverride -}}
+{{ .Values.clusterName }}-{{ .Values.nodeGroup }}
+{{- else -}}
+{{ .Values.nameOverride }}-{{ .Values.nodeGroup }}
+{{- end -}}
+{{- else -}}
+{{ .Values.fullnameOverride }}
+{{- end -}}
+{{- end -}}
+
+{{- define "opensearch.masterService" -}}
+{{- if empty .Values.masterService -}}
+{{- if empty .Values.fullnameOverride -}}
+{{- if empty .Values.nameOverride -}}
+{{ .Values.clusterName }}-master
+{{- else -}}
+{{ .Values.nameOverride }}-master
+{{- end -}}
+{{- else -}}
+{{ .Values.fullnameOverride }}
+{{- end -}}
+{{- else -}}
+{{ .Values.masterService }}
+{{- end -}}
+{{- end -}}
+
+{{- define "opensearch.serviceName" -}}
+{{- if eq .Values.nodeGroup "master" }}
+{{- include "opensearch.masterService" . }}
+{{- else }}
+{{- include "opensearch.uname" . }}
+{{- end }}
+{{- end -}}
+
+{{- define "opensearch.endpoints" -}}
+{{- $replicas := int (toString (.Values.replicas)) }}
+{{- $uname := (include "opensearch.uname" .) }}
+ {{- range $i, $e := untilStep 0 $replicas 1 -}}
+{{ $uname }}-{{ $i }},
+ {{- end -}}
+{{- end -}}
+
+{{- define "opensearch.majorVersion" -}}
+{{- if .Values.majorVersion }}
+ {{- .Values.majorVersion }}
+{{- else }}
+ {{- $version := semver (coalesce .Values.image.tag .Chart.AppVersion "1") }}
+ {{- $version.Major }}
+{{- end }}
+{{- end }}
+
+{{- define "opensearch.dockerRegistry" -}}
+{{- if eq .Values.global.dockerRegistry "" -}}
+ {{- .Values.global.dockerRegistry -}}
+{{- else -}}
+ {{- .Values.global.dockerRegistry | trimSuffix "/" | printf "%s/" -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "opensearch.roles" -}}
+{{- range $.Values.roles -}}
+{{ . }},
+{{- end -}}
+{{- end -}}
+
+{{/*
+Return the appropriate apiVersion for ingress.
+*/}}
+{{- define "opensearch.ingress.apiVersion" -}}
+ {{- if and (.Capabilities.APIVersions.Has "networking.k8s.io/v1") (semverCompare ">= 1.19-0" .Capabilities.KubeVersion.Version) -}}
+ {{- print "networking.k8s.io/v1" -}}
+ {{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
+ {{- print "networking.k8s.io/v1beta1" -}}
+ {{- else -}}
+ {{- print "extensions/v1beta1" -}}
+ {{- end -}}
+{{- end -}}
+
+{{/*
+Return if ingress is stable.
+*/}}
+{{- define "opensearch.ingress.isStable" -}}
+ {{- eq (include "opensearch.ingress.apiVersion" .) "networking.k8s.io/v1" -}}
+{{- end -}}
+{{/*
+Return if ingress supports ingressClassName.
+*/}}
+{{- define "opensearch.ingress.supportsIngressClassName" -}}
+ {{- or (eq (include "opensearch.ingress.isStable" .) "true") (and (eq (include "opensearch.ingress.apiVersion" .) "networking.k8s.io/v1beta1") (semverCompare ">= 1.18-0" .Capabilities.KubeVersion.Version)) -}}
+{{- end -}}
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/configmap.yaml b/opensearch-bk/helm-charts/charts/opensearch/templates/configmap.yaml
new file mode 100644
index 00000000..4f2961be
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/configmap.yaml
@@ -0,0 +1,18 @@
+{{- $root := . }}
+{{- if .Values.config }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ template "opensearch.uname" . }}-config
+ labels:
+ {{- include "opensearch.labels" . | nindent 4 }}
+data:
+{{- range $configName, $configYaml := .Values.config }}
+ {{ $configName }}: |
+ {{- if (eq (kindOf $configYaml) "map")}}
+ {{- tpl (toYaml $configYaml) $root | nindent 4 }}
+ {{- else -}}
+ {{- tpl $configYaml $root | nindent 4 }}
+ {{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/extraManifests.yaml b/opensearch-bk/helm-charts/charts/opensearch/templates/extraManifests.yaml
new file mode 100644
index 00000000..2855904e
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/extraManifests.yaml
@@ -0,0 +1,4 @@
+{{ range .Values.extraObjects }}
+---
+{{ tpl (toYaml .) $ }}
+{{ end }}
\ No newline at end of file
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/ingress.yaml b/opensearch-bk/helm-charts/charts/opensearch/templates/ingress.yaml
new file mode 100644
index 00000000..7a4d0da8
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/ingress.yaml
@@ -0,0 +1,62 @@
+{{- if .Values.ingress.enabled -}}
+{{- $fullName := include "opensearch.serviceName" . -}}
+{{- $servicePort := .Values.httpPort -}}
+{{- $ingressPath := .Values.ingress.path -}}
+{{- $ingressApiIsStable := eq (include "opensearch.ingress.isStable" .) "true" -}}
+{{- $ingressSupportsIngressClassName := eq (include "opensearch.ingress.supportsIngressClassName" .) "true" -}}
+{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1
+{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1beta1
+{{- else -}}
+apiVersion: extensions/v1beta1
+{{- end }}
+kind: Ingress
+metadata:
+ name: {{ $fullName }}
+ labels:
+ {{- include "opensearch.labels" . | nindent 4 }}
+{{- with .Values.ingress.annotations }}
+ annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+ {{- if and $ingressSupportsIngressClassName .Values.ingress.ingressClassName }}
+ ingressClassName: {{ .Values.ingress.ingressClassName }}
+ {{- end -}}
+{{- if .Values.ingress.tls }}
+ tls:
+ {{- range .Values.ingress.tls }}
+ - hosts:
+ {{- range .hosts }}
+ - {{ . }}
+ {{- end }}
+ secretName: {{ .secretName }}
+ {{- end }}
+{{- end }}
+ rules:
+ {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . | quote }}
+ http:
+ paths:
+ - path: {{ $ingressPath }}
+ pathType: Prefix
+ backend:
+ service:
+ name: {{ $fullName }}
+ port:
+ number: {{ $servicePort }}
+ {{- end }}
+ {{- else -}}
+ {{- range .Values.ingress.hosts }}
+ - host: {{ . | quote }}
+ http:
+ paths:
+ - path: {{ $ingressPath }}
+ backend:
+ serviceName: {{ $fullName }}
+ servicePort: {{ $servicePort }}
+ {{- end }}
+ {{- end }}
+{{- end }}
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/networkpolicy.yaml b/opensearch-bk/helm-charts/charts/opensearch/templates/networkpolicy.yaml
new file mode 100644
index 00000000..51cd2635
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/networkpolicy.yaml
@@ -0,0 +1,17 @@
+{{- if .Values.networkPolicy.create -}}
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+ name: {{ template "opensearch.uname" . }}-opensearch-net
+ labels:
+ {{- include "opensearch.labels" . | nindent 4 }}
+spec:
+ ingress:
+ - from:
+ - podSelector:
+ matchLabels:
+ {{ template "opensearch.uname" . }}-transport-client: "true"
+ podSelector:
+ matchLabels:
+ {{ template "opensearch.uname" . }}-transport-client: "true"
+{{- end }}
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/poddisruptionbudget.yaml b/opensearch-bk/helm-charts/charts/opensearch/templates/poddisruptionbudget.yaml
new file mode 100644
index 00000000..68ab5b69
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/poddisruptionbudget.yaml
@@ -0,0 +1,17 @@
+{{- if .Values.maxUnavailable }}
+{{- if semverCompare ">=1.21-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: policy/v1
+{{- else -}}
+apiVersion: policy/v1beta1
+{{- end }}
+kind: PodDisruptionBudget
+metadata:
+ name: "{{ template "opensearch.uname" . }}-pdb"
+ labels:
+ {{- include "opensearch.labels" . | nindent 4 }}
+spec:
+ maxUnavailable: {{ .Values.maxUnavailable }}
+ selector:
+ matchLabels:
+ {{- include "opensearch.selectorLabels" . | nindent 6 }}
+{{- end }}
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/podsecuritypolicy.yaml b/opensearch-bk/helm-charts/charts/opensearch/templates/podsecuritypolicy.yaml
new file mode 100644
index 00000000..76f36fad
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/podsecuritypolicy.yaml
@@ -0,0 +1,17 @@
+{{- if semverCompare "<1.25-0" .Capabilities.KubeVersion.GitVersion -}}
+{{- if .Values.podSecurityPolicy.create -}}
+{{- $fullName := include "opensearch.uname" . -}}
+apiVersion: policy/v1beta1
+kind: PodSecurityPolicy
+metadata:
+ name: {{ default $fullName .Values.podSecurityPolicy.name | quote }}
+ labels:
+ {{- include "opensearch.labels" . | nindent 4 }}
+spec:
+{{ toYaml .Values.podSecurityPolicy.spec | indent 2 }}
+{{- if .Values.sysctl.enabled }}
+ allowedUnsafeSysctls:
+ - vm.max_map_count
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/role.yaml b/opensearch-bk/helm-charts/charts/opensearch/templates/role.yaml
new file mode 100644
index 00000000..cba3cf99
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/role.yaml
@@ -0,0 +1,22 @@
+{{- if .Values.rbac.create -}}
+{{- $fullName := include "opensearch.uname" . -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: {{ $fullName | quote }}
+ labels:
+ {{- include "opensearch.labels" . | nindent 4 }}
+rules:
+ - apiGroups:
+ - extensions
+ resources:
+ - podsecuritypolicies
+ resourceNames:
+ {{- if eq .Values.podSecurityPolicy.name "" }}
+ - {{ $fullName | quote }}
+ {{- else }}
+ - {{ .Values.podSecurityPolicy.name | quote }}
+ {{- end }}
+ verbs:
+ - use
+{{- end -}}
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/rolebinding.yaml b/opensearch-bk/helm-charts/charts/opensearch/templates/rolebinding.yaml
new file mode 100644
index 00000000..04455179
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/rolebinding.yaml
@@ -0,0 +1,21 @@
+{{- if .Values.rbac.create -}}
+{{- $fullName := include "opensearch.uname" . -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: {{ $fullName | quote }}
+ labels:
+ {{- include "opensearch.labels" . | nindent 4 }}
+subjects:
+ - kind: ServiceAccount
+ {{- if eq .Values.rbac.serviceAccountName "" }}
+ name: {{ $fullName | quote }}
+ {{- else }}
+ name: {{ .Values.rbac.serviceAccountName | quote }}
+ {{- end }}
+ namespace: {{ .Release.Namespace | quote }}
+roleRef:
+ kind: Role
+ name: {{ $fullName | quote }}
+ apiGroup: rbac.authorization.k8s.io
+{{- end -}}
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/securityconfig.yaml b/opensearch-bk/helm-charts/charts/opensearch/templates/securityconfig.yaml
new file mode 100644
index 00000000..13d6364b
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/securityconfig.yaml
@@ -0,0 +1,19 @@
+{{- if .Values.securityConfig.config.data -}}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ include "opensearch.uname" . }}-securityconfig
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "opensearch.labels" . | nindent 4 }}
+type: Opaque
+stringData:
+{{- range $key, $val := .Values.securityConfig.config.data }}
+ {{ $key }}: |
+ {{- if (eq (kindOf $val) "map")}}
+ {{- tpl (toYaml $val) $ | nindent 4 }}
+ {{- else }}
+ {{- tpl $val $ | nindent 4 }}
+ {{- end }}
+{{- end }}
+{{- end }}
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/service.yaml b/opensearch-bk/helm-charts/charts/opensearch/templates/service.yaml
new file mode 100644
index 00000000..3b74924f
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/service.yaml
@@ -0,0 +1,62 @@
+---
+kind: Service
+apiVersion: v1
+metadata:
+ name: {{ template "opensearch.serviceName" . }}
+ labels:
+ {{- include "opensearch.labels" . | nindent 4 }}
+{{- if .Values.service.labels }}
+{{ toYaml .Values.service.labels | indent 4 }}
+{{- end }}
+ annotations:
+{{ toYaml .Values.service.annotations | indent 4 }}
+spec:
+ type: {{ .Values.service.type }}
+ selector:
+ {{- include "opensearch.selectorLabels" . | nindent 4 }}
+ ports:
+ - name: {{ .Values.service.httpPortName | default "http" }}
+ protocol: TCP
+ port: {{ .Values.httpPort }}
+{{- if .Values.service.nodePort }}
+ nodePort: {{ .Values.service.nodePort }}
+{{- end }}
+ - name: {{ .Values.service.transportPortName | default "transport" }}
+ protocol: TCP
+ port: {{ .Values.transportPort }}
+{{- if .Values.service.loadBalancerIP }}
+ loadBalancerIP: {{ .Values.service.loadBalancerIP }}
+{{- end }}
+{{- with .Values.service.loadBalancerSourceRanges }}
+ loadBalancerSourceRanges:
+{{ toYaml . | indent 4 }}
+{{- end }}
+{{- if .Values.service.externalTrafficPolicy }}
+ externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }}
+{{- end }}
+---
+kind: Service
+apiVersion: v1
+metadata:
+ name: {{ template "opensearch.serviceName" . }}-headless
+ labels:
+ {{- include "opensearch.labels" . | nindent 4 }}
+{{- if .Values.service.labelsHeadless }}
+{{ toYaml .Values.service.labelsHeadless | indent 4 }}
+{{- end }}
+ annotations:
+ service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
+{{- if .Values.service.headless.annotations }}
+{{ toYaml .Values.service.headless.annotations | indent 4 }}
+{{- end }}
+spec:
+ clusterIP: None # This is needed for statefulset hostnames like opensearch-0 to resolve
+ # Create endpoints also if the related pod isn't ready
+ publishNotReadyAddresses: true
+ selector:
+ {{- include "opensearch.selectorLabels" . | nindent 4 }}
+ ports:
+ - name: {{ .Values.service.httpPortName | default "http" }}
+ port: {{ .Values.httpPort }}
+ - name: {{ .Values.service.transportPortName | default "transport" }}
+ port: {{ .Values.transportPort }}
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/serviceaccount.yaml b/opensearch-bk/helm-charts/charts/opensearch/templates/serviceaccount.yaml
new file mode 100644
index 00000000..81e2fcf2
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/serviceaccount.yaml
@@ -0,0 +1,17 @@
+{{- if .Values.rbac.create -}}
+{{- $fullName := include "opensearch.uname" . -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ {{- if eq .Values.rbac.serviceAccountName "" }}
+ name: {{ $fullName | quote }}
+ {{- else }}
+ name: {{ .Values.rbac.serviceAccountName | quote }}
+ {{- end }}
+ labels:
+ {{- include "opensearch.labels" . | nindent 4 }}
+ annotations:
+ {{- with .Values.rbac.serviceAccountAnnotations }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{- end -}}
diff --git a/opensearch-bk/helm-charts/charts/opensearch/templates/statefulset.yaml b/opensearch-bk/helm-charts/charts/opensearch/templates/statefulset.yaml
new file mode 100644
index 00000000..83b0c86c
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/templates/statefulset.yaml
@@ -0,0 +1,525 @@
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: {{ template "opensearch.uname" . }}
+ labels:
+ {{- include "opensearch.labels" . | nindent 4 }}
+ annotations:
+ majorVersion: "{{ include "opensearch.majorVersion" . }}"
+spec:
+ serviceName: {{ template "opensearch.serviceName" . }}-headless
+ selector:
+ matchLabels:
+ {{- include "opensearch.selectorLabels" . | nindent 6 }}
+ {{- if .Values.singleNode }}
+ replicas: 1
+ {{- else }}
+ replicas: {{ .Values.replicas }}
+ {{- end }}
+ podManagementPolicy: {{ .Values.podManagementPolicy }}
+ updateStrategy:
+ type: {{ .Values.updateStrategy }}
+ {{- if .Values.persistence.enabled }}
+ volumeClaimTemplates:
+ - metadata:
+ name: {{ template "opensearch.uname" . }}
+ {{- if .Values.persistence.labels.enabled }}
+ labels:
+ {{- include "opensearch.labels" . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.persistence.annotations }}
+ annotations:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ spec:
+ accessModes:
+ {{- range .Values.persistence.accessModes }}
+ - {{ . | quote }}
+ {{- end }}
+ resources:
+ requests:
+ storage: {{ .Values.persistence.size | quote }}
+ {{- if .Values.persistence.storageClass }}
+ {{- if (eq "-" .Values.persistence.storageClass) }}
+ storageClassName: ""
+ {{- else }}
+ storageClassName: "{{ .Values.persistence.storageClass }}"
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ template:
+ metadata:
+ name: "{{ template "opensearch.uname" . }}"
+ labels:
+ {{- include "opensearch.labels" . | nindent 8 }}
+ annotations:
+ {{- range $key, $value := .Values.podAnnotations }}
+ {{ $key }}: {{ $value | quote }}
+ {{- end }}
+ {{- /* This forces a restart if the configmap has changed */}}
+ {{- if .Values.config }}
+ configchecksum: {{ include (print .Template.BasePath "/configmap.yaml") . | sha256sum | trunc 63 }}
+ {{- end }}
+ {{- if .Values.securityConfig.config.data }}
+ securityconfigchecksum: {{ include (print .Template.BasePath "/securityconfig.yaml") . | sha256sum | trunc 63 }}
+ {{- end }}
+ spec:
+ {{- if .Values.schedulerName }}
+ schedulerName: "{{ .Values.schedulerName }}"
+ {{- end }}
+ securityContext:
+{{ toYaml .Values.podSecurityContext | indent 8 }}
+ {{- if .Values.sysctl.enabled }}
+ sysctls:
+ - name: vm.max_map_count
+ value: {{ .Values.sysctlVmMaxMapCount | quote }}
+ {{- end }}
+ {{- if .Values.fsGroup }}
+ fsGroup: {{ .Values.fsGroup }} # Deprecated value, please use .Values.podSecurityContext.fsGroup
+ {{- end }}
+ {{- if and .Values.rbac.create (eq .Values.rbac.serviceAccountName "") }}
+ serviceAccountName: "{{ template "opensearch.uname" . }}"
+ {{- else }}
+ serviceAccountName: {{ .Values.rbac.serviceAccountName | quote }}
+ {{- end }}
+ {{- with .Values.tolerations }}
+ tolerations:
+{{ toYaml . | indent 6 }}
+ {{- end }}
+ {{- with .Values.nodeSelector }}
+ nodeSelector:
+{{ toYaml . | indent 8 }}
+ {{- end }}
+ {{- if or (eq .Values.antiAffinity "hard") (eq .Values.antiAffinity "soft") .Values.nodeAffinity }}
+ {{- if .Values.priorityClassName }}
+ priorityClassName: {{ .Values.priorityClassName }}
+ {{- end }}
+ affinity:
+ {{- end }}
+ {{- if eq .Values.antiAffinity "hard" }}
+ podAntiAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ - labelSelector:
+ matchExpressions:
+ - key: app.kubernetes.io/instance
+ operator: In
+ values:
+ - {{ .Release.Name }}
+ - key: app.kubernetes.io/name
+ operator: In
+ values:
+ - {{ include "opensearch.name" . }}
+ topologyKey: {{ .Values.antiAffinityTopologyKey }}
+ {{- else if eq .Values.antiAffinity "soft" }}
+ podAntiAffinity:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ - weight: 1
+ podAffinityTerm:
+ topologyKey: {{ .Values.antiAffinityTopologyKey }}
+ labelSelector:
+ matchExpressions:
+ - key: app.kubernetes.io/instance
+ operator: In
+ values:
+ - {{ .Release.Name }}
+ - key: app.kubernetes.io/name
+ operator: In
+ values:
+ - {{ include "opensearch.name" . }}
+ {{- end }}
+ {{- with .Values.nodeAffinity }}
+ nodeAffinity:
+{{ toYaml . | indent 10 }}
+ {{- end }}
+ {{- if .Values.topologySpreadConstraints }}
+ topologySpreadConstraints:
+ {{- toYaml .Values.topologySpreadConstraints | nindent 8 }}
+ {{- end }}
+ terminationGracePeriodSeconds: {{ .Values.terminationGracePeriod }}
+ volumes:
+ {{- range .Values.secretMounts }}
+ - name: {{ .name | required "secretMount .name is required" }}
+ secret:
+ secretName: {{ .secretName | required "secretMount .secretName is required" }}
+ {{- if .defaultMode }}
+ defaultMode: {{ .defaultMode }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.config }}
+ - name: config
+ configMap:
+ name: {{ template "opensearch.uname" . }}-config
+ {{- end }}
+ {{- if and .Values.securityConfig.config.data .Values.securityConfig.config.securityConfigSecret }}
+ {{ fail "Only one of .Values.securityConfig.config.data and .Values.securityConfig.config.securityConfigSecret may be defined. Please see the comment in values.yaml describing usage." }}
+ {{- end }}
+ {{- if .Values.securityConfig.config.data }}
+ - name: security-config-data
+ secret:
+ secretName: {{ include "opensearch.uname" . }}-securityconfig
+ {{- end }}
+ {{- with .Values.securityConfig.config.securityConfigSecret }}
+ - name: security-config-complete
+ secret:
+ secretName: {{ . | quote }}
+ {{- end }}
+ {{- if .Values.securityConfig.actionGroupsSecret }}
+ - name: action-groups
+ secret:
+ secretName: {{ .Values.securityConfig.actionGroupsSecret }}
+ {{- end }}
+ {{- if .Values.securityConfig.configSecret }}
+ - name: security-config
+ secret:
+ secretName: {{ .Values.securityConfig.configSecret }}
+ {{- end }}
+ {{- if .Values.securityConfig.internalUsersSecret }}
+ - name: internal-users-config
+ secret:
+ secretName: {{ .Values.securityConfig.internalUsersSecret }}
+ {{- end }}
+ {{- if .Values.securityConfig.rolesSecret }}
+ - name: roles
+ secret:
+ secretName: {{ .Values.securityConfig.rolesSecret }}
+ {{- end }}
+ {{- if .Values.securityConfig.rolesMappingSecret }}
+ - name: role-mapping
+ secret:
+ secretName: {{ .Values.securityConfig.rolesMappingSecret }}
+ {{- end -}}
+ {{- if .Values.securityConfig.tenantsSecret }}
+ - name: tenants
+ secret:
+ secretName: {{ .Values.securityConfig.tenantsSecret }}
+ {{- end }}
+{{- if .Values.keystore }}
+ - name: keystore
+ emptyDir: {}
+ {{- range .Values.keystore }}
+ - name: keystore-{{ .secretName }}
+ secret: {{ toYaml . | nindent 12 }}
+ {{- end }}
+{{ end }}
+ {{- if .Values.extraVolumes }}
+ # Currently some extra blocks accept strings
+ # to continue with backwards compatibility this is being kept
+ # whilst also allowing for yaml to be specified too.
+ {{- if eq "string" (printf "%T" .Values.extraVolumes) }}
+{{ tpl .Values.extraVolumes . | indent 6 }}
+ {{- else }}
+{{ toYaml .Values.extraVolumes | indent 6 }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.imagePullSecrets }}
+ imagePullSecrets:
+{{ toYaml .Values.imagePullSecrets | indent 8 }}
+ {{- end }}
+ enableServiceLinks: {{ .Values.enableServiceLinks }}
+ {{- if .Values.hostAliases }}
+ hostAliases: {{ toYaml .Values.hostAliases | nindent 8 }}
+ {{- end }}
+ {{- if or (.Values.extraInitContainers) (.Values.keystore) (.Values.persistence.enabled) (.Values.sysctlInit.enabled) }}
+ initContainers:
+{{- if and .Values.persistence.enabled .Values.persistence.enableInitChown }}
+ - name: fsgroup-volume
+ image: "{{ template "opensearch.dockerRegistry" . }}{{ .Values.persistence.image | default "busybox" }}:{{ .Values.persistence.imageTag | default "latest" }}"
+ command: ['sh', '-c']
+ args:
+ - 'chown -R 1000:1000 /usr/share/opensearch/data'
+ securityContext:
+ runAsUser: 0
+ resources:
+ {{ toYaml .Values.initResources | nindent 10 }}
+ volumeMounts:
+ - name: "{{ template "opensearch.uname" . }}"
+ mountPath: {{ .Values.opensearchHome }}/data
+{{- end }}
+{{- if .Values.sysctlInit.enabled }}
+ - name: sysctl
+ image: "{{ template "opensearch.dockerRegistry" . }}{{ .Values.sysctlInit.image | default "busybox" }}:{{ .Values.sysctlInit.imageTag | default "latest" }}"
+ imagePullPolicy: "{{ .Values.image.pullPolicy }}"
+ command:
+ - sh
+ - -c
+ - |
+ set -xe
+ DESIRED="{{ .Values.sysctlVmMaxMapCount }}"
+ CURRENT=$(sysctl -n vm.max_map_count)
+ if [ "$DESIRED" -gt "$CURRENT" ]; then
+ sysctl -w vm.max_map_count=$DESIRED
+ fi
+ securityContext:
+ runAsUser: 0
+ privileged: true
+ resources:
+ {{ toYaml .Values.initResources | nindent 10 }}
+{{- end }}
+{{ if .Values.keystore }}
+ - name: keystore
+ image: "{{ template "opensearch.dockerRegistry" . }}{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+ imagePullPolicy: "{{ .Values.image.pullPolicy }}"
+ command:
+ - sh
+ - -c
+ - |
+ #!/usr/bin/env bash
+ set -euo pipefail
+
+ {{ .Values.opensearchHome }}/bin/opensearch-keystore create
+
+ for i in /tmp/keystoreSecrets/*/*; do
+ key=$(basename $i)
+ echo "Adding file $i to keystore key $key"
+ {{ .Values.opensearchHome }}/bin/opensearch-keystore add-file "$key" "$i"
+ done
+
+ # Add the bootstrap password since otherwise the opensearch entrypoint tries to do this on startup
+ if [ ! -z ${PASSWORD+x} ]; then
+ echo 'Adding env $PASSWORD to keystore as key bootstrap.password'
+ echo "$PASSWORD" | {{ .Values.opensearchHome }}/bin/opensearch-keystore add -x bootstrap.password
+ fi
+
+ cp -a {{ .Values.opensearchHome }}/config/opensearch.keystore /tmp/keystore/
+ env: {{ toYaml .Values.extraEnvs | nindent 10 }}
+ envFrom: {{ toYaml .Values.envFrom | nindent 10 }}
+ resources:
+ {{ toYaml .Values.initResources | nindent 10 }}
+ volumeMounts:
+ - name: keystore
+ mountPath: /tmp/keystore
+ {{- range .Values.keystore }}
+ - name: keystore-{{ .secretName }}
+ mountPath: /tmp/keystoreSecrets/{{ .secretName }}
+ {{- end }}
+{{ end }}
+ {{- if .Values.extraInitContainers }}
+ # Currently some extra blocks accept strings
+ # to continue with backwards compatibility this is being kept
+ # whilst also allowing for yaml to be specified too.
+ {{- if eq "string" (printf "%T" .Values.extraInitContainers) }}
+{{ tpl .Values.extraInitContainers . | indent 6 }}
+ {{- else }}
+{{ toYaml .Values.extraInitContainers | indent 6 }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ containers:
+ - name: "{{ template "opensearch.name" . }}"
+ securityContext:
+{{ toYaml .Values.securityContext | indent 10 }}
+ {{- if .Values.plugins.enabled }}
+ command:
+ - sh
+ - -c
+ - |
+ #!/usr/bin/env bash
+ set -euo pipefail
+
+ {{- range $plugin := .Values.plugins.installList }}
+ ./bin/opensearch-plugin install -b {{ $plugin }}
+ {{- end }}
+
+ bash opensearch-docker-entrypoint.sh
+ {{- end }}
+
+ image: "{{ template "opensearch.dockerRegistry" . }}{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+ imagePullPolicy: "{{ .Values.image.pullPolicy }}"
+ readinessProbe:
+{{ toYaml .Values.readinessProbe | indent 10 }}
+ {{- if .Values.livenessProbe }}
+ livenessProbe:
+{{ toYaml .Values.livenessProbe | indent 10 }}
+ {{- end }}
+ {{- if semverCompare ">=1.16-0" .Capabilities.KubeVersion.Version }}
+ startupProbe:
+{{ toYaml .Values.startupProbe | indent 10 }}
+ {{- end }}
+ ports:
+ - name: http
+ containerPort: {{ .Values.httpPort }}
+ - name: transport
+ containerPort: {{ .Values.transportPort }}
+ resources:
+{{ toYaml .Values.resources | indent 10 }}
+ env:
+ - name: node.name
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ {{- if (and (has "master" .Values.roles) (not .Values.singleNode)) }}
+ - name: cluster.initial_master_nodes
+ value: "{{ template "opensearch.endpoints" . }}"
+ {{- end }}
+ - name: discovery.seed_hosts
+ value: "{{ template "opensearch.masterService" . }}-headless"
+ - name: cluster.name
+ value: "{{ .Values.clusterName }}"
+ - name: network.host
+ value: "{{ .Values.networkHost }}"
+ - name: OPENSEARCH_JAVA_OPTS
+ value: "{{ .Values.opensearchJavaOpts }}"
+ - name: node.roles
+ value: "{{ template "opensearch.roles" . }}"
+ {{- if .Values.singleNode }}
+ - name: discovery.type
+ value: "single-node"
+ {{- end }}
+{{- if .Values.extraEnvs }}
+{{ toYaml .Values.extraEnvs | indent 8 }}
+{{- end }}
+{{- if .Values.envFrom }}
+ envFrom:
+{{ toYaml .Values.envFrom | indent 8 }}
+{{- end }}
+ volumeMounts:
+ {{- if .Values.persistence.enabled }}
+ - name: "{{ template "opensearch.uname" . }}"
+ mountPath: {{ .Values.opensearchHome }}/data
+ {{- end }}
+ {{- if .Values.keystore }}
+ - name: keystore
+ mountPath: {{ .Values.opensearchHome }}/config/opensearch.keystore
+ subPath: opensearch.keystore
+ {{- end }}
+ {{- if .Values.securityConfig.enabled }}
+ {{- if .Values.securityConfig.actionGroupsSecret }}
+ - mountPath: {{ .Values.securityConfig.path }}/action_groups.yml
+ name: action-groups
+ subPath: action_groups.yml
+ {{- end }}
+ {{- if .Values.securityConfig.configSecret }}
+ - mountPath: {{ .Values.securityConfig.path }}/config.yml
+ name: security-config
+ subPath: config.yml
+ {{- end }}
+ {{- if .Values.securityConfig.internalUsersSecret }}
+ - mountPath: {{ .Values.securityConfig.path }}/internal_users.yml
+ name: internal-users-config
+ subPath: internal_users.yml
+ {{- end }}
+ {{- if .Values.securityConfig.rolesSecret }}
+ - mountPath: {{ .Values.securityConfig.path }}/roles.yml
+ name: roles
+ subPath: roles.yml
+ {{- end }}
+ {{- if .Values.securityConfig.rolesMappingSecret }}
+ - mountPath: {{ .Values.securityConfig.path }}/roles_mapping.yml
+ name: role-mapping
+ subPath: roles_mapping.yml
+ {{- end }}
+ {{- if .Values.securityConfig.tenantsSecret }}
+ - mountPath: {{ .Values.securityConfig.path }}/tenants.yml
+ name: tenants
+ subPath: tenants.yml
+ {{- end }}
+ {{- if .Values.securityConfig.config.data }}
+ {{- if .Values.securityConfig.config.dataComplete }}
+ - mountPath: {{ .Values.securityConfig.path }}
+ name: security-config-data
+ {{- else }}
+ {{- range $key, $_ := .Values.securityConfig.config.data }}
+ - mountPath: {{ $.Values.securityConfig.path }}/{{ $key }}
+ name: security-config-data
+ subPath: {{ $key }}
+ {{- end }}
+ {{- end }}
+ {{- else if .Values.securityConfig.config.securityConfigSecret }}
+ - mountPath: {{ .Values.securityConfig.path }}
+ name: security-config-complete
+ {{- end }}
+ {{- end }}
+ {{- range .Values.secretMounts }}
+ - name: {{ .name | required "secretMount .name is required" }}
+ mountPath: {{ .path | required "secretMount .path is required" }}
+ {{- if .subPath }}
+ subPath: {{ .subPath }}
+ {{- end }}
+ {{- end }}
+ {{- range $path, $config := .Values.config }}
+ - name: config
+ mountPath: {{ $.Values.opensearchHome }}/config/{{ $path }}
+ subPath: {{ $path }}
+ {{- end -}}
+ {{- if .Values.extraVolumeMounts }}
+ # Currently some extra blocks accept strings
+ # to continue with backwards compatibility this is being kept
+ # whilst also allowing for yaml to be specified too.
+ {{- if eq "string" (printf "%T" .Values.extraVolumeMounts) }}
+{{ tpl .Values.extraVolumeMounts . | indent 8 }}
+ {{- else }}
+{{ toYaml .Values.extraVolumeMounts | indent 8 }}
+ {{- end }}
+ {{- end }}
+ {{- if .Values.masterTerminationFix }}
+ {{- if has "master" .Values.roles }}
+ # This sidecar will prevent slow master re-election
+ - name: opensearch-master-graceful-termination-handler
+ image: "{{ template "opensearch.dockerRegistry" . }}{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+ imagePullPolicy: "{{ .Values.image.pullPolicy }}"
+ command:
+ - "sh"
+ - -c
+ - |
+ #!/usr/bin/env bash
+ set -eo pipefail
+
+ http () {
+ local path="${1}"
+ if [ -n "${USERNAME}" ] && [ -n "${PASSWORD}" ]; then
+ BASIC_AUTH="-u ${USERNAME}:${PASSWORD}"
+ else
+ BASIC_AUTH=''
+ fi
+ curl -XGET -s -k --fail ${BASIC_AUTH} {{ .Values.protocol }}://{{ template "opensearch.masterService" . }}:{{ .Values.httpPort }}${path}
+ }
+
+ cleanup () {
+ while true ; do
+ local master="$(http "/_cat/master?h=node" || echo "")"
+ if [[ $master == "{{ template "opensearch.masterService" . }}"* && $master != "${NODE_NAME}" ]]; then
+ echo "This node is not master."
+ break
+ fi
+ echo "This node is still master, waiting gracefully for it to step down"
+ sleep 1
+ done
+
+ exit 0
+ }
+
+ trap cleanup SIGTERM
+
+ sleep infinity &
+ wait $!
+ resources:
+{{ toYaml .Values.sidecarResources | indent 10 }}
+ env:
+ - name: NODE_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ {{- if .Values.extraEnvs }}
+{{ toYaml .Values.extraEnvs | indent 8 }}
+ {{- end }}
+ {{- if .Values.envFrom }}
+ envFrom:
+{{ toYaml .Values.envFrom | indent 8 }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+{{- if .Values.lifecycle }}
+ lifecycle:
+{{ toYaml .Values.lifecycle | indent 10 }}
+{{- end }}
+ {{- if .Values.extraContainers }}
+ # Currently some extra blocks accept strings
+ # to continue with backwards compatibility this is being kept
+ # whilst also allowing for yaml to be specified too.
+ {{- if eq "string" (printf "%T" .Values.extraContainers) }}
+{{ tpl .Values.extraContainers . | indent 6 }}
+ {{- else }}
+{{ toYaml .Values.extraContainers | indent 6 }}
+ {{- end }}
+ {{- end }}
diff --git a/opensearch-bk/helm-charts/charts/opensearch/values.yaml b/opensearch-bk/helm-charts/charts/opensearch/values.yaml
new file mode 100644
index 00000000..88660433
--- /dev/null
+++ b/opensearch-bk/helm-charts/charts/opensearch/values.yaml
@@ -0,0 +1,478 @@
+---
+clusterName: "opensearch-cluster"
+nodeGroup: "master"
+
+# If discovery.type in the opensearch configuration is set to "single-node",
+# this should be set to "true"
+# If "true", replicas will be forced to 1
+#singleNode: false
+singleNode: true #changed
+
+# The service that non master groups will try to connect to when joining the cluster
+# This should be set to clusterName + "-" + nodeGroup for your master group
+masterService: "opensearch-cluster-master"
+
+# OpenSearch roles that will be applied to this nodeGroup
+# These will be set as environment variable "node.roles". E.g. node.roles=master,ingest,data,remote_cluster_client
+roles:
+ - master
+ - ingest
+ - data
+ - remote_cluster_client
+
+#replicas: 3
+replicas: 1 #changed
+
+# if not set, falls back to parsing .Values.imageTag, then .Chart.appVersion.
+majorVersion: ""
+
+global:
+ # Set if you want to change the default docker registry, e.g. a private one.
+ dockerRegistry: ""
+
+# Allows you to add any config files in {{ .Values.opensearchHome }}/config
+opensearchHome: /usr/share/opensearch
+# such as opensearch.yml and log4j2.properties
+config:
+ # Values must be YAML literal style scalar / YAML multiline string.
+ # : |
+ #
+ # log4j2.properties: |
+ # status = error
+ #
+ # appender.console.type = Console
+ # appender.console.name = console
+ # appender.console.layout.type = PatternLayout
+ # appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker %m%n
+ #
+ # rootLogger.level = info
+ # rootLogger.appenderRef.console.ref = console
+ opensearch.yml: |
+ cluster.name: opensearch-cluster
+
+ # Bind to all interfaces because we don't know what IP address Docker will assign to us.
+ network.host: 0.0.0.0
+
+ # Setting network.host to a non-loopback address enables the annoying bootstrap checks. "Single-node" mode disables them again.
+ # Implicitly done if ".singleNode" is set to "true".
+ # discovery.type: single-node
+
+ # Start OpenSearch Security Demo Configuration
+ # WARNING: revise all the lines below before you go into production
+ plugins:
+ security:
+ ssl:
+ transport:
+ pemcert_filepath: esnode.pem
+ pemkey_filepath: esnode-key.pem
+ pemtrustedcas_filepath: root-ca.pem
+ enforce_hostname_verification: false
+ http:
+ enabled: true
+ pemcert_filepath: esnode.pem
+ pemkey_filepath: esnode-key.pem
+ pemtrustedcas_filepath: root-ca.pem
+ allow_unsafe_democertificates: true
+ allow_default_init_securityindex: true
+ authcz:
+ admin_dn:
+ - CN=kirk,OU=client,O=client,L=test,C=de
+ audit.type: internal_opensearch
+ enable_snapshot_restore_privilege: true
+ check_snapshot_restore_write_privileges: true
+ restapi:
+ roles_enabled: ["all_access", "security_rest_api_access"]
+ system_indices:
+ enabled: true
+ indices:
+ [
+ ".opendistro-alerting-config",
+ ".opendistro-alerting-alert*",
+ ".opendistro-anomaly-results*",
+ ".opendistro-anomaly-detector*",
+ ".opendistro-anomaly-checkpoints",
+ ".opendistro-anomaly-detection-state",
+ ".opendistro-reports-*",
+ ".opendistro-notifications-*",
+ ".opendistro-notebooks",
+ ".opendistro-asynchronous-search-response*",
+ ]
+ ######## End OpenSearch Security Demo Configuration ########
+ # log4j2.properties:
+
+# Extra environment variables to append to this nodeGroup
+# This will be appended to the current 'env:' key. You can use any of the kubernetes env
+# syntax here
+extraEnvs: []
+# - name: MY_ENVIRONMENT_VAR
+# value: the_value_goes_here
+
+# Allows you to load environment variables from kubernetes secret or config map
+envFrom: []
+# - secretRef:
+# name: env-secret
+# - configMapRef:
+# name: config-map
+
+# A list of secrets and their paths to mount inside the pod
+# This is useful for mounting certificates for security and for mounting
+# the X-Pack license
+secretMounts: []
+
+hostAliases: []
+# - ip: "127.0.0.1"
+# hostnames:
+# - "foo.local"
+# - "bar.local"
+
+image:
+ repository: "opensearchproject/opensearch"
+ # override image tag, which is .Chart.AppVersion by default
+ tag: ""
+ pullPolicy: "IfNotPresent"
+
+podAnnotations: {}
+ # iam.amazonaws.com/role: es-cluster
+
+# additionals labels
+labels: {}
+
+opensearchJavaOpts: "-Xmx512M -Xms512M"
+
+resources:
+ requests:
+ cpu: "1000m"
+ memory: "100Mi"
+
+initResources: {}
+# limits:
+# cpu: "25m"
+# memory: "128Mi"
+# requests:
+# cpu: "25m"
+# memory: "128Mi"
+
+sidecarResources: {}
+# limits:
+# cpu: "25m"
+# memory: "128Mi"
+# requests:
+# cpu: "25m"
+# memory: "128Mi"
+
+networkHost: "0.0.0.0"
+
+rbac:
+ create: false
+ serviceAccountAnnotations: {}
+ serviceAccountName: ""
+
+podSecurityPolicy:
+ create: false
+ name: ""
+ spec:
+ privileged: true
+ fsGroup:
+ rule: RunAsAny
+ runAsUser:
+ rule: RunAsAny
+ seLinux:
+ rule: RunAsAny
+ supplementalGroups:
+ rule: RunAsAny
+ volumes:
+ - secret
+ - configMap
+ - persistentVolumeClaim
+ - emptyDir
+
+persistence:
+ enabled: true
+ # Set to false to disable the `fsgroup-volume` initContainer that will update permissions on the persistent disk.
+ enableInitChown: true
+ # override image, which is busybox by default
+ # image: busybox
+ # override image tag, which is latest by default
+ # imageTag:
+ labels:
+ # Add default labels for the volumeClaimTemplate of the StatefulSet
+ enabled: false
+ # OpenSearch Persistent Volume Storage Class
+ # If defined, storageClassName:
+ # If set to "-", storageClassName: "", which disables dynamic provisioning
+ # If undefined (the default) or set to null, no storageClassName spec is
+ # set, choosing the default provisioner. (gp2 on AWS, standard on
+ # GKE, AWS & OpenStack)
+ #
+ # storageClass: "-"
+ accessModes:
+ - ReadWriteOnce
+ size: 8Gi
+ annotations: {}
+
+extraVolumes: []
+ # - name: extras
+ # emptyDir: {}
+
+extraVolumeMounts: []
+ # - name: extras
+ # mountPath: /usr/share/extras
+ # readOnly: true
+
+extraContainers: []
+ # - name: do-something
+ # image: busybox
+ # command: ['do', 'something']
+
+extraInitContainers: []
+ # - name: do-somethings
+ # image: busybox
+ # command: ['do', 'something']
+
+# This is the PriorityClass settings as defined in
+# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
+priorityClassName: ""
+
+# By default this will make sure two pods don't end up on the same node
+# Changing this to a region would allow you to spread pods across regions
+antiAffinityTopologyKey: "kubernetes.io/hostname"
+
+# Hard means that by default pods will only be scheduled if there are enough nodes for them
+# and that they will never end up on the same node. Setting this to soft will do this "best effort"
+antiAffinity: "soft"
+
+# This is the node affinity settings as defined in
+# https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature
+nodeAffinity: {}
+
+# This is the pod topology spread constraints
+# https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
+topologySpreadConstraints: []
+
+# The default is to deploy all pods serially. By setting this to parallel all pods are started at
+# the same time when bootstrapping the cluster
+podManagementPolicy: "Parallel"
+
+# The environment variables injected by service links are not used, but can lead to slow OpenSearch boot times when
+# there are many services in the current namespace.
+# If you experience slow pod startups you probably want to set this to `false`.
+enableServiceLinks: true
+
+protocol: https
+httpPort: 9200
+transportPort: 9300
+
+service:
+ labels: {}
+ labelsHeadless: {}
+ headless:
+ annotations: {}
+ type: ClusterIP
+ nodePort: ""
+ annotations: {}
+ httpPortName: http
+ transportPortName: transport
+ loadBalancerIP: ""
+ loadBalancerSourceRanges: []
+ externalTrafficPolicy: ""
+
+updateStrategy: RollingUpdate
+
+# This is the max unavailable setting for the pod disruption budget
+# The default value of 1 will make sure that kubernetes won't allow more than 1
+# of your pods to be unavailable during maintenance
+maxUnavailable: 1
+
+podSecurityContext:
+ fsGroup: 1000
+ runAsUser: 1000
+
+securityContext:
+ capabilities:
+ drop:
+ - ALL
+ # readOnlyRootFilesystem: true
+ runAsNonRoot: true
+ runAsUser: 1000
+
+securityConfig:
+ enabled: true
+ path: "/usr/share/opensearch/plugins/opensearch-security/securityconfig"
+ actionGroupsSecret:
+ configSecret:
+ internalUsersSecret:
+ rolesSecret:
+ rolesMappingSecret:
+ tenantsSecret:
+ # The following option simplifies securityConfig by using a single secret and
+ # specifying the config files as keys in the secret instead of creating
+ # different secrets for for each config file.
+ # Note that this is an alternative to the individual secret configuration
+ # above and shouldn't be used if the above secrets are used.
+ config:
+ # There are multiple ways to define the configuration here:
+ # * If you define anything under data, the chart will automatically create
+ # a secret and mount it.
+ # * If you define securityConfigSecret, the chart will assume this secret is
+ # created externally and mount it.
+ # * It is an error to define both data and securityConfigSecret.
+ securityConfigSecret: ""
+ dataComplete: true
+ data: {}
+ # config.yml: |-
+ # internal_users.yml: |-
+ # roles.yml: |-
+ # roles_mapping.yml: |-
+ # action_groups.yml: |-
+ # tenants.yml: |-
+
+# How long to wait for opensearch to stop gracefully
+terminationGracePeriod: 120
+
+sysctlVmMaxMapCount: 262144
+
+startupProbe:
+ tcpSocket:
+ port: 9200
+ initialDelaySeconds: 5
+ periodSeconds: 10
+ timeoutSeconds: 3
+ failureThreshold: 30
+
+livenessProbe: {}
+ # periodSeconds: 20
+ # timeoutSeconds: 5
+ # failureThreshold: 10
+ # successThreshold: 1
+ # initialDelaySeconds: 10
+ # tcpSocket:
+ # port: 9200
+
+readinessProbe:
+ tcpSocket:
+ port: 9200
+ periodSeconds: 5
+ timeoutSeconds: 3
+ failureThreshold: 3
+
+## Use an alternate scheduler.
+## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
+##
+schedulerName: ""
+
+imagePullSecrets: []
+nodeSelector: {}
+tolerations: []
+
+# Enabling this will publically expose your OpenSearch instance.
+# Only enable this if you have security enabled on your cluster
+ingress:
+ enabled: false
+ # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName
+ # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress
+ # ingressClassName: nginx
+
+ annotations: {}
+ # kubernetes.io/ingress.class: nginx
+ # kubernetes.io/tls-acme: "true"
+ path: /
+ hosts:
+ - chart-example.local
+ tls: []
+ # - secretName: chart-example-tls
+ # hosts:
+ # - chart-example.local
+
+nameOverride: ""
+fullnameOverride: ""
+
+masterTerminationFix: false
+
+lifecycle: {}
+ # preStop:
+ # exec:
+ # command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
+ # postStart:
+ # exec:
+ # command:
+ # - bash
+ # - -c
+ # - |
+ # #!/bin/bash
+ # # Add a template to adjust number of shards/replicas1
+ # TEMPLATE_NAME=my_template
+ # INDEX_PATTERN="logstash-*"
+ # SHARD_COUNT=8
+ # REPLICA_COUNT=1
+ # ES_URL=http://localhost:9200
+ # while [[ "$(curl -s -o /dev/null -w '%{http_code}\n' $ES_URL)" != "200" ]]; do sleep 1; done
+ # curl -XPUT "$ES_URL/_template/$TEMPLATE_NAME" -H 'Content-Type: application/json' -d'{"index_patterns":['\""$INDEX_PATTERN"\"'],"settings":{"number_of_shards":'$SHARD_COUNT',"number_of_replicas":'$REPLICA_COUNT'}}'
+
+keystore: []
+# To add secrets to the keystore:
+# - secretName: opensearch-encryption-key
+
+networkPolicy:
+ create: false
+ ## Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now.
+ ## In order for a Pod to access OpenSearch, it needs to have the following label:
+ ## {{ template "uname" . }}-client: "true"
+ ## Example for default configuration to access HTTP port:
+ ## opensearch-master-http-client: "true"
+ ## Example for default configuration to access transport port:
+ ## opensearch-master-transport-client: "true"
+
+ http:
+ enabled: false
+
+# Deprecated
+# please use the above podSecurityContext.fsGroup instead
+fsGroup: ""
+
+## Set optimal sysctl's through securityContext. This requires privilege. Can be disabled if
+## the system has already been preconfigured. (Ex: https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html)
+## Also see: https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/
+sysctl:
+ enabled: false
+
+## Set optimal sysctl's through privileged initContainer.
+sysctlInit:
+ enabled: false
+ # override image, which is busybox by default
+ # image: busybox
+ # override image tag, which is latest by default
+ # imageTag:
+
+## Enable to add 3rd Party / Custom plugins not offered in the default OpenSearch image.
+plugins:
+ enabled: false
+ installList: []
+ # - example-fake-plugin
+
+# -- Array of extra K8s manifests to deploy
+extraObjects: []
+ # - apiVersion: secrets-store.csi.x-k8s.io/v1
+ # kind: SecretProviderClass
+ # metadata:
+ # name: argocd-secrets-store
+ # spec:
+ # provider: aws
+ # parameters:
+ # objects: |
+ # - objectName: "argocd"
+ # objectType: "secretsmanager"
+ # jmesPath:
+ # - path: "client_id"
+ # objectAlias: "client_id"
+ # - path: "client_secret"
+ # objectAlias: "client_secret"
+ # secretObjects:
+ # - data:
+ # - key: client_id
+ # objectName: client_id
+ # - key: client_secret
+ # objectName: client_secret
+ # secretName: argocd-secrets-store
+ # type: Opaque
+ # labels:
+ # app.kubernetes.io/part-of: argocd
diff --git a/opensearch-bk/helm-charts/ct.yaml b/opensearch-bk/helm-charts/ct.yaml
new file mode 100644
index 00000000..d523e917
--- /dev/null
+++ b/opensearch-bk/helm-charts/ct.yaml
@@ -0,0 +1,3 @@
+# See https://github.com/helm/chart-testing#configuration
+target-branch: main
+helm-extra-args: --timeout 1000s
diff --git a/opensearch-fluentbit-stack/README.md b/opensearch-fluentbit-stack/README.md
new file mode 100644
index 00000000..a38e3085
--- /dev/null
+++ b/opensearch-fluentbit-stack/README.md
@@ -0,0 +1,262 @@
+
+Table of Contents
+=================
+
+- [Table of Contents](#table-of-contents)
+- [OpenSearch-k8s-operator](#opensearch-k8s-operator)
+ - [How does the operator work](#how-does-the-operator-work)
+ - [Installation](#installation)
+ - [Deploying a new OpenSearch cluster](#deploying-a-new-opensearch-cluster)
+- [Fluent bit](#fluent-bit)
+ - [Installation](#installation-1)
+- [OpenSearch Dashboards](#opensearch-dashboards)
+- [Reference links](#reference-links)
+
+# OpenSearch-k8s-operator
+
+The Kubernetes OpenSearch Operator is used for automating the deployment, provisioning, management, and orchestration of OpenSearch clusters and OpenSearch dashboards.
+
+Using the Operator makes scaling up and down, version upgrades, rolling restarts, adjustment of memory and disk resources on the nodes, securing deployments, and managing certificates simplified and streamlined.
+
+The Operator consists of tho main parts :
+
+1) CRD --> Custom Resource Definition which declares the OpenSearch cluster.
+2) Operator manager (itself!)
+
+## How does the operator work
+
+The OpenSearch operator follows the normal kubernetes operator model.
+
+It is controlled by several Custom Resources (CR), defined in Kubernetes using a Custom Resource Definition (CRD), that act as the API/interface for the operator.
+
+This approach integrates the operator into the normal declarative model and thinking of the Kubernetes API, making it easy to use and automate.
+
+The main resource offered by the operator is called `OpenSearchCluster` and is a spec for an OpenSearch cluster to be deployed in kubernetes.
+
+Additional resources are `OpensearchRole`, `OpensearchUser` and `OpensearchUserRoleBinding` which expose a declarative API to managing users and roles in OpenSearch.
+
+For each custom resource the operator runs a controller. This controller connects to the kubernetes API and watches for changes in custom objects belonging to its custom resource (for example a newly created `OpenSearchCluster` object).
+
+For each object a reconcile loop is started and the main `Reconcile` method is called. This main method acts as an orchestrator and calls a number of reconcilers.
+
+Each reconciler is responsible for one aspect of managing an OpenSearch cluster (for example there is one that deals with deploying the dashboards instance and one dealing with the management of the securityconfig).
+
+The reconcile run is repeated regularly (called requeing) so that the reconcilers can react to any changes to the cluster. In case the custom object is changed a new reconcile run is triggered immediately.
+
+## Installation
+
+In this section, we are going to install operator in kubernetes cluster.
+
+We are going to use [Opster / opensearch-k8s-operator](https://github.com/Opster/opensearch-k8s-operator) repository which is also uploaded to [ArtifactHub](https://artifacthub.io/packages/helm/opensearch-operator/opensearch-operator) (similar to OperatorHub). It's just an artifact that knows how to save kubernetes helm packages.
+
+Using helm chart:
+
+We will change directory:
+
+```shell
+cd opensearch-operator
+```
+
+By running below command, it will install the manager that operates all the OpenSearch Operator's actions:
+
+```shell
+helm install my-opensearch-operator . -f values.yaml
+```
+
+The chart has deployed in the environment.
+
+Output:
+```Output
+NAME: my-opensearch-operator
+LAST DEPLOYED: Wed Nov 23 14:44:51 2022
+NAMESPACE: opensearch
+STATUS: deployed
+REVISION: 1
+TEST SUITE: None
+```
+
+The below command will show us the status of the chart deployment.
+```shell
+helm ls
+```
+
+Output:
+```Output
+NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
+my-opensearch-operator opensearch 1 2022-11-23 14:44:51.904455841 +0530 IST deployed opensearch-operator-2.1.1 2.1.1
+```
+
+Now, we will check what has been deployed:
+
+```shell
+kubectl get all
+```
+
+Output:
+```Output
+
+NAME READY STATUS RESTARTS AGE
+pod/opensearch-operator-controller-manager-6f6f5bdf49-nndfz 2/2 Running 0 6m22s
+
+NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
+service/opensearch-operator-controller-manager-metrics-service ClusterIP 10.43.137.113 8443/TCP 6m23s
+
+NAME READY UP-TO-DATE AVAILABLE AGE
+deployment.apps/opensearch-operator-controller-manager 1/1 1 1 6m23s
+
+NAME DESIRED CURRENT READY AGE
+replicaset.apps/opensearch-operator-controller-manager-6f6f5bdf49 1 1 1 6m23s
+```
+
+To check CRD installation:
+
+```shell
+kubectl get crd | grep opensearch
+```
+
+Output:
+
+```Output
+NAME CREATED AT
+opensearchclusters.opensearch.opster.io 2022-11-23T09:14:59Z
+opensearchroles.opensearch.opster.io 2022-11-23T09:14:58Z
+opensearchuserrolebindings.opensearch.opster.io 2022-11-23T09:14:58Z
+opensearchusers.opensearch.opster.io 2022-11-23T09:14:58Z
+```
+
+## Deploying a new OpenSearch cluster
+
+ Review `opensearch-v2-cluster.yaml` and create the resources by running following command:
+
+```shell
+kubectl apply -f opensearch-v2-cluster.yaml
+```
+
+![opensearch-cluster-status](/images/opensearch-cluster-status.png)
+
+By running following command we can see opensearch cluster name:
+
+```shell
+kubectl get opensearch
+```
+
+To access the OpenSearch REST API, run:
+
+```shell
+kubectl port-forward svc/my-first-cluster 9200
+```
+
+Then open a second terminal and run:
+
+```shell
+curl -k -u admin:admin https://localhost:9200/_cat/nodes?v
+```
+
+You should see the three deployed pods listed. (You can also see in the browser by typing `https://localhost:9200/_cat/nodes?v` URL.)
+
+![OpenSearch-REST-API-curl](/images/OpenSearch-REST-API-curl.png)
+
+![OpenSearch-REST-API](/images/OpenSearch-REST-API.png)
+
+
+# Fluent bit
+
+Fluent bit workflow is to collect, parse, filter and ship logs to a central place. One of the critical phases of may is the ability to do *buffering*.
+
+Buffering is a mechanism to place processed data into a temporary location until is ready to be shipped.
+
+By default when Fluent Bit processes data, it uses Memory as a primary and temporary place to store the records, but there are certain scenarios where it would be ideal to have a persistent buffering mechanism based in the filesystem to provide aggregation and data safety capabilities.
+
+## Installation
+
+In this section, we are going to install fluent bit in kubernetes cluster.
+
+Create `fluent-bit` folder:
+
+```shell
+mkdir fluent-bit
+```
+
+Pull fluent-bit helm chat:
+
+```shell
+ helm pull fluent/fluent-bit
+```
+
+You will see `fluent-bit-0.21.3.tgz` in your directory:
+
+```shell
+ls
+```
+
+Extract to fluent-bit folder:
+
+```shell
+ tar -xvzf fluent-bit-0.21.3.tgz -C fluent-bit
+```
+
+Delete `fluent-bit-0.21.3.tgz`:
+
+```shell
+rm -rf fluent-bit-0.21.3.tgz
+```
+
+Change directory to `fluent-bit` folder:
+
+```shell
+cd fluent-bit
+```
+
+Install `fluent-bit` by running below command:
+
+```shell
+helm install fluentbit . -f values.yaml
+```
+
+Get the status of the resources:
+
+```shell
+kubectl get all | grep fluent
+```
+
+Check logs for one of the `fluent-bit` pod:
+
+```shell
+k logs fluentbit-fluent-bit-9kk58
+```
+
+Truncated output:
+```Output
+[ info] [storage] ver=1.3.0, type=memory+filesystem, sync=normal, checksum=off, max_chunks_up=128
+[storage] backlog input plugin: storage_backlog.2
+[ info] [input:tail:tail.0] storage_strategy='filesystem' (memory + filesystem)
+```
+
+# OpenSearch Dashboards
+
+We can login to OpenSearch Dashboards by running:
+
+```shell
+kubectl port-forward svc/my-first-cluster-dashboards 5601
+```
+
+Open [https://localhost:5601](https://localhost:5601/) in the browser and log in with the default demo credentials `admin / admin`.
+
+Click on Menu button (hamburger button) on top left side, Navigate to `Management` > `Stack Management` > `Index Patterns` and follow below images for the next steps:
+
+![Create-Index-Pattern-Opensearch-Operator](/images/Create-Index-Pattern-Opensearch-Operator.png)
+![Defined-Index-Pattern-Opensearch-Operator](/images/Defined-Index-Pattern-Opensearch-Operator.png)
+
+![Create-Index-Pattern-Operator](/images/Create-Index-Pattern-Operator.png)
+
+Go to the **OpenSearch Dashboards** > **Discover** to visualize the logs:
+
+![Discover-logs-Opensearch-Operator](../images/Discover-logs-Opensearch-Operator.png)
+
+# Reference links
+
+[Kubernetes Operator for OpenSearch](https://opensearch.org/blog/technical-post/2022/04/launching-open-source-operator-for-openSearch/)
+
+[OpenSearch-k8s-operator github repository](https://github.com/Opster/opensearch-k8s-operator)
+
+[Buffering & Storage](https://docs.fluentbit.io/manual/administration/buffering-and-storage)
\ No newline at end of file
diff --git a/opensearch-fluentbit-stack/fluent-bit/.helmignore b/opensearch-fluentbit-stack/fluent-bit/.helmignore
new file mode 100644
index 00000000..0e8a0eb3
--- /dev/null
+++ b/opensearch-fluentbit-stack/fluent-bit/.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/opensearch-fluentbit-stack/fluent-bit/Chart.yaml b/opensearch-fluentbit-stack/fluent-bit/Chart.yaml
new file mode 100644
index 00000000..ec9de8cd
--- /dev/null
+++ b/opensearch-fluentbit-stack/fluent-bit/Chart.yaml
@@ -0,0 +1,27 @@
+annotations:
+ artifacthub.io/changes: |
+ - kind: changed
+ description: "Update Fluent Bit configuration files URL"
+apiVersion: v1
+appVersion: 2.0.5
+description: Fast and lightweight log processor and forwarder or Linux, OSX and BSD
+ family operating systems.
+home: https://fluentbit.io/
+icon: https://raw.githubusercontent.com/cncf/artwork/master/projects/fluentd/fluentbit/icon/fluentbit-icon-color.svg
+keywords:
+- logging
+- fluent-bit
+- fluentd
+maintainers:
+- email: eduardo@calyptia.com
+ name: edsiper
+- email: naseem@transit.app
+ name: naseemkullah
+- email: towmeykaw@gmail.com
+ name: Towmeykaw
+- email: steve.hipwell@gmail.com
+ name: stevehipwell
+name: fluent-bit
+sources:
+- https://github.com/fluent/fluent-bit/
+version: 0.21.3
diff --git a/opensearch-fluentbit-stack/fluent-bit/README.md b/opensearch-fluentbit-stack/fluent-bit/README.md
new file mode 100644
index 00000000..6920d3d7
--- /dev/null
+++ b/opensearch-fluentbit-stack/fluent-bit/README.md
@@ -0,0 +1,57 @@
+# Fluent Bit Helm chart
+
+[Fluent Bit](https://fluentbit.io) is a fast and lightweight log processor and forwarder or Linux, OSX and BSD family operating systems.
+
+## Installation
+
+To add the `fluent` helm repo, run:
+
+```sh
+helm repo add fluent https://fluent.github.io/helm-charts
+```
+
+To install a release named `fluent-bit`, run:
+
+```sh
+helm install fluent-bit fluent/fluent-bit
+```
+
+## Chart values
+
+```sh
+helm show values fluent/fluent-bit
+```
+
+## Using Lua scripts
+Fluent Bit allows us to build filter to modify the incoming records using custom [Lua scripts.](https://docs.fluentbit.io/manual/pipeline/filters/lua)
+
+### How to use Lua scripts with this Chart
+
+First, you should add your Lua scripts to `luaScripts` in values.yaml, for example:
+
+```yaml
+luaScripts:
+ filter_example.lua: |
+ function filter_name(tag, timestamp, record)
+ -- put your lua code here.
+ end
+```
+
+After that, the Lua scripts will be ready to be used as filters. So next step is to add your Fluent bit [filter](https://docs.fluentbit.io/manual/concepts/data-pipeline/filter) to `config.filters` in values.yaml, for example:
+
+```yaml
+config:
+ filters: |
+ [FILTER]
+ Name lua
+ Match
+ script /fluent-bit/scripts/filter_example.lua
+ call filter_name
+```
+Under the hood, the chart will:
+- Create a configmap using `luaScripts`.
+- Add a volumeMounts for each Lua scripts using the path `/fluent-bit/scripts/