diff --git a/.gitignore b/.gitignore index 01d35d64e78c71576561c45c892462bf54e98fd0..c62d1f07832209612e81446d1790673055a1b110 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,8 @@ .classpath /.settings +compose/kubedir/config +kubernetes/helm/openslice/files/org.etsi.osl.cridge/kubeconfig.yaml +kubernetes/helm/openslice/files/org.etsi.osl.portal.web/src/js/config.js +kubernetes/helm/openslice/files/org.etsi.osl.tmf.web/src/assets/config/config.prod.json +kubernetes/helm/openslice/files/org.etsi.osl.tmf.web/src/assets/config/theming.scss diff --git a/compose/docker-compose.yaml.configure b/compose/docker-compose.yaml.configure index 5026f35d2509cd4ca9da16e6a5b647aa5177d58d..ad992e72dfa223717105e82c4db193a6de64759a 100644 --- a/compose/docker-compose.yaml.configure +++ b/compose/docker-compose.yaml.configure @@ -86,8 +86,8 @@ services: logging: driver: "json-file" options: - max-size: "200m" - max-file: "5" + max-size: "400m" + max-file: "3" ports: - 8080:8080 - 8443:8443 @@ -164,7 +164,7 @@ services: logging: driver: "json-file" options: - max-size: "800m" + max-size: "500m" max-file: "3" ports: - 13011:13011 @@ -239,7 +239,7 @@ services: driver: "json-file" options: max-size: "1g" - max-file: "3" + max-file: "2" volumes: - ./repo:/root ports: @@ -272,7 +272,7 @@ services: driver: "json-file" options: max-size: "1g" - max-file: "3" + max-file: "2" ports: - 13100:13100 networks: @@ -387,7 +387,7 @@ services: oslmcp: container_name: openslice-mcp restart: always - profiles: ["prod"] + profiles: ["prod", "mcp-server", "mcp"] build: context: ../../org.etsi.osl.mcp.server/ dockerfile: Dockerfile @@ -416,12 +416,66 @@ services: logging: driver: "json-file" options: - max-size: "500m" + max-size: "250m" max-file: "2" networks: - front - back + + + oslmcpbackend: + container_name: openslice-mcp-backend + restart: always + profiles: ["prod", "mcp-backend", "mcp"] + build: + context: ../../org.etsi.osl.mcp.backend/ + dockerfile: Dockerfile + image: labs.etsi.org:5050/osl/code/org.etsi.osl.mcp.backend:latest + ports: + - "11880:11880" + environment: + SPRING_APPLICATION_JSON: '{ + "server.forward-headers-strategy":"FRAMEWORK" + }' + + SERVER_PORT: 11880 + SPRING_APPLICATION_NAME: osl-mcp-backend + + # AI Configuration + SPRING_AI_OLLAMA_BASE_URL: http://ollama:11434 # Change the Ollama API here + SPRING_AI_OLLAMA_CHAT_MODEL: gpt-oss:20b # Change the used model here + SPRING_AI_OLLAMA_CHAT_TEMPERATURE: 0.5 + SPRING_AI_CHAT_SYSTEM_PROMPT: "You are an OpenSlice AI Assistant." # Customize your initial Assistant prompt + SPRING_AI_CHAT_MAX_MESSAGES: 100 + + # MCP Client Configuration + SPRING_AI_MCP_CLIENT_TYPE: SYNC + SPRING_AI_MCP_CLIENT_STREAMABLE_HTTP_CONNECTIONS_OPENSLICE_SERVER_URL: http://openslice-mcp:13015/sse + + # OAuth2/Keycloak Configuration + SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: http://keycloak:8080/auth/realms/openslice + SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_ISSUER_URI: http://keycloak:8080/auth/realms/openslice + SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_CLIENT_ID: osapiWebClientId + + # ActiveMQ Configuration + SPRING_ACTIVEMQ_BROKER_URL: tcp://anartemis:61616?jms.watchTopicAdvisories=false + SPRING_ACTIVEMQ_USER: artemis + SPRING_ACTIVEMQ_PASSWORD: artemis + + # Logging Configuration + LOGGING_LEVEL_ROOT: INFO + LOGGING_LEVEL_OSL: INFO + LOGGING_LEVEL_SPRING_AI: INFO + logging: + driver: "json-file" + options: + max-size: "250m" + max-file: "2" + networks: + - back + - front + portainer: container_name: portainer image: portainer/portainer-ce:2.18.4 @@ -479,7 +533,7 @@ services: driver: "json-file" options: max-size: "500m" - max-file: "3" + max-file: "2" ports: - "8000:8000" networks: diff --git a/compose/keycloak-init/realm-export.json b/compose/keycloak-init/realm-export.json index f74761ad1204c69097b2b036d532a717fce21b75..513473787968f08a170419eab2829f312862960b 100644 --- a/compose/keycloak-init/realm-export.json +++ b/compose/keycloak-init/realm-export.json @@ -39,6 +39,20 @@ "failureFactor": 30, "roles": { "realm": [ + { + "id": "4f485a21-80c6-466e-8241-b3942aadf93a", + "name": "OSL_AUTOACK_ORDER", + "description": "This OSL role is used to allow issuing Service Orders, which are auto-acknowledged, without the need for approval", + "composite": true, + "composites": { + "realm": [ + "USER" + ] + }, + "clientRole": false, + "containerId": "openslice", + "attributes": {} + }, { "id": "1741dd77-ee50-4fd7-bec6-1a6d3d9d778a", "name": "MENTOR", @@ -77,6 +91,7 @@ { "id": "a2685809-e874-4009-8435-92ded0c7180d", "name": "ADMIN", + "description": "This OSL role is used to access the admin views and perform administrative tasks (you need at least one user at this role to setup the system)", "composite": true, "composites": { "realm": [ diff --git a/compose/nginx/nginx.conf.default b/compose/nginx/nginx.conf.default index c2478c41a224135c92dcbc547e1aa8ff5d917171..7e72ecd44b3290c33b67776f736771aca4ec7828 100644 --- a/compose/nginx/nginx.conf.default +++ b/compose/nginx/nginx.conf.default @@ -98,6 +98,14 @@ http { # proxy_set_header X-Forwarded-Proto $scheme; # proxy_set_header X-Forwarded-Port 443; # } + + location /ask { + proxy_pass http://oslmcpbackend:11880/ask; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-Proto $scheme; + } } diff --git a/kubernetes/helm/openslice/Chart.yaml b/kubernetes/helm/openslice/Chart.yaml index 506eb599e0f01c98092568510fa2fa7eaff9c5a3..14eaee8389759446a78315ba3161901bc97395e5 100644 --- a/kubernetes/helm/openslice/Chart.yaml +++ b/kubernetes/helm/openslice/Chart.yaml @@ -15,9 +15,9 @@ 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.1.0 +version: 3.0.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. -appVersion: 2025Q2 +appVersion: 2025Q4 diff --git a/kubernetes/helm/openslice/files/keycloak-init/realm-export.json b/kubernetes/helm/openslice/files/keycloak-init/realm-export.json index 0be17ce27cf1cb144b41ee61b22c774305645a33..16043a42629902c171d815c1f56c0ccd33c36634 100644 --- a/kubernetes/helm/openslice/files/keycloak-init/realm-export.json +++ b/kubernetes/helm/openslice/files/keycloak-init/realm-export.json @@ -39,6 +39,20 @@ "failureFactor": 30, "roles": { "realm": [ + { + "id": "4f485a21-80c6-466e-8241-b3942aadf93a", + "name": "OSL_AUTOACK_ORDER", + "description": "This OSL role is used to allow issuing Service Orders, which are auto-acknowledged, without the need for approval", + "composite": true, + "composites": { + "realm": [ + "USER" + ] + }, + "clientRole": false, + "containerId": "openslice", + "attributes": {} + }, { "id": "1741dd77-ee50-4fd7-bec6-1a6d3d9d778a", "name": "MENTOR", @@ -77,6 +91,7 @@ { "id": "a2685809-e874-4009-8435-92ded0c7180d", "name": "ADMIN", + "description": "This OSL role is used to access the admin views and perform administrative tasks (you need at least one user at this role to setup the system)", "composite": true, "composites": { "realm": [ diff --git a/kubernetes/helm/openslice/files/mysql-init/01-databases.sql b/kubernetes/helm/openslice/files/mysql-init/01-databases.sql deleted file mode 100644 index aa16eecb933a0d47f811532a7fd8c7185800482c..0000000000000000000000000000000000000000 --- a/kubernetes/helm/openslice/files/mysql-init/01-databases.sql +++ /dev/null @@ -1,11 +0,0 @@ -# create databases -CREATE DATABASE IF NOT EXISTS `{{ .Values.oscreds.mysql.openslicedb | default "osdb" }}`; -CREATE DATABASE IF NOT EXISTS `{{ .Values.oscreds.mysql.keycloak.database | default "keycloak" }}`; - -# create portal user and grant rights -CREATE USER '{{ .Values.oscreds.mysql.portal.username | default "portaluser" }}'@'localhost' IDENTIFIED BY '{{ .Values.oscreds.mysql.portal.password | default "12345" }}'; -GRANT ALL PRIVILEGES ON *.* TO '{{ .Values.oscreds.mysql.portal.username | default "portaluser" }}'@'%' IDENTIFIED BY '{{ .Values.oscreds.mysql.portal.password | default "12345" }}'; - -# create keycloak user and grant rights -CREATE USER '{{ .Values.oscreds.mysql.keycloak.username | default "keycloak" }}'@'localhost' IDENTIFIED BY '{{ .Values.oscreds.mysql.keycloak.password | default "password" }}'; -GRANT ALL PRIVILEGES ON *.* TO '{{ .Values.oscreds.mysql.keycloak.username | default "keycloak" }}'@'%' IDENTIFIED BY '{{ .Values.oscreds.mysql.keycloak.password | default "password" }}'; diff --git a/kubernetes/helm/openslice/files/mysql-init/entrypoint.sh b/kubernetes/helm/openslice/files/mysql-init/entrypoint.sh new file mode 100644 index 0000000000000000000000000000000000000000..e9e6bcdd96cc757b13efbff71fe4b9209328cfc0 --- /dev/null +++ b/kubernetes/helm/openslice/files/mysql-init/entrypoint.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env sh +set -eu + +run_mysql() { + mysql -u root -p"$MYSQL_ROOT_PASSWORD" "$@" +} + +echo "Waiting for database to be ready" + +until run_mysql -e 'SELECT 1'; do + sleep 1 +done + +echo "Creating databases and users" + +create_user() { + if ! run_mysql --execute "CREATE USER '$1'@'%' IDENTIFIED BY '$2';" 2>/dev/null; then + run_mysql --execute "ALTER USER '$1'@'%' IDENTIFIED BY '$2';" + fi +} + +PORTAL_USER="$(< /var/run/secrets/portal/username)" +PORTAL_DATABASE="$(< /var/run/secrets/portal/database)" + +TMF_USER="$(< /var/run/secrets/tmf/username)" +TMF_DATABASE="$(< /var/run/secrets/tmf/database)" + +KEYCLOAK_USER="$(< /var/run/secrets/keycloak/username)" +KEYCLOAK_DATABASE="$(< /var/run/secrets/keycloak/database)" + +METRICO_USER="$(< /var/run/secrets/metrico/username)" +METRICO_DATABASE="$(< /var/run/secrets/metrico/database)" + +run_mysql --execute \ +" +# create databases +CREATE DATABASE IF NOT EXISTS $PORTAL_DATABASE; +CREATE DATABASE IF NOT EXISTS $TMF_DATABASE; +CREATE DATABASE IF NOT EXISTS $KEYCLOAK_DATABASE; +CREATE DATABASE IF NOT EXISTS $METRICO_DATABASE; +" + +create_user "$PORTAL_USER" "$(< /var/run/secrets/portal/password)" +create_user "$TMF_USER" "$(< /var/run/secrets/tmf/password)" +create_user "$KEYCLOAK_USER" "$(< /var/run/secrets/keycloak/password)" +create_user "$METRICO_USER" "$(< /var/run/secrets/metrico/password)" + +run_mysql --execute \ +" +# Grant portal user rights to the portal database +GRANT ALL PRIVILEGES ON $PORTAL_DATABASE.* TO '$PORTAL_USER'@'%'; +# Grant tmf user rights to the tmf database +GRANT ALL PRIVILEGES ON $TMF_DATABASE.* TO '$TMF_USER'@'%'; +# Grant keycloak user rights to the portal database +GRANT ALL PRIVILEGES ON $KEYCLOAK_DATABASE.* TO '$KEYCLOAK_USER'@'%'; +# Grant metrico user rights to the portal database +GRANT ALL PRIVILEGES ON $METRICO_DATABASE.* TO '$METRICO_USER'@'%'; +" + +echo "Finished creating databases and users" diff --git a/kubernetes/helm/openslice/files/org.etsi.osl.tmf.web/src/assets/config/config.prod.default.json b/kubernetes/helm/openslice/files/org.etsi.osl.tmf.web/src/assets/config/config.prod.default.json index 1d0bb9bae6fc33f8c2d2839da0a01f52bd836247..34e17316da08ef5ab18d88db8f0ce6450c374a10 100644 --- a/kubernetes/helm/openslice/files/org.etsi.osl.tmf.web/src/assets/config/config.prod.default.json +++ b/kubernetes/helm/openslice/files/org.etsi.osl.tmf.web/src/assets/config/config.prod.default.json @@ -1,10 +1,11 @@ { "TITLE": "OpenSlice by ETSI", - "PORTALVERSION":"2024Q2", + "PORTALVERSION":"2025Q4", "WIKI": "https://osl.etsi.org/documentation", "BUGZILLA": "{BASEURL}/bugzilla/", "STATUS": "{BASEURL}/healthstatus/", "WEBURL": "{BASEURL}", + "ASSISTANT_URL": "{BASEURL}/ask", "PORTAL_REPO_APIURL": "{BASEURL}/osapi", "ASSURANCE_SERVICE_MGMT_APIURL": "{BASEURL}/oas-api", "APITMFURL": "{BASEURL}/tmf-api", diff --git a/kubernetes/helm/openslice/files/org.etsi.osl.tmf.web/src/assets/config/config.theming.default.json b/kubernetes/helm/openslice/files/org.etsi.osl.tmf.web/src/assets/config/config.theming.default.json index 0db3bf0e0708d7218a03f56c68434c7454345fd4..2b9445b679c3e7e6a4d701718471342a5d668a1f 100644 --- a/kubernetes/helm/openslice/files/org.etsi.osl.tmf.web/src/assets/config/config.theming.default.json +++ b/kubernetes/helm/openslice/files/org.etsi.osl.tmf.web/src/assets/config/config.theming.default.json @@ -1,9 +1,9 @@ { -"THEME_ID":"default", -"DEPLOYMENT_LOGO_PATH":"assets/images/logo_clear.png", -"DEFAULT_SERVICE_LOGO_PATH":"assets/images/logo_icon_original.png", -"FAVICON_PATH":"favicon.ico", -"WHO_WE_ARE_HTML":"
ETSI SDG OpenSlice|https://osl.etsi.org
The ETSI Software Development Group for OpenSlice (SDG OSL) is developing an open source service based Operations Support System (OSS) to deliver Network Slice as a Service (NSaaS).
OpenSlice by ETSI|http://portal.openslice.io
A portal that allows 5G experimenters to design and deploy network services towards the infrastructure.
OpenSlice by ETSI wiki|https://osl.etsi.org/documentation
A wiki containing OpenSlice software documentation.
", -"CONNECT_WITH_US_HTML":"
LinkedIn
Slack
Twitter
", -"FOOTER_HTML":"
OpenSlice has received funding from various projects under European Programmes for research, technological development and demonstration. You may refer to our extensive ecosystem for further details.
Openslice by ETSI running OSL version 2024Q2 | Terms and Conditions | © 2024 on behalf of osl.etsi.org
" -} + "THEME_ID":"default", + "DEPLOYMENT_LOGO_PATH":"assets/images/logo_clear.png", + "DEFAULT_SERVICE_LOGO_PATH":"assets/images/logo_icon_original.png", + "FAVICON_PATH":"favicon.ico", + "WHO_WE_ARE_HTML":"
OpenSlice By ETSI Portal
OpenSlice By ETSI Wiki
ETSI SDG OpenSlice

OpenSlice by ETSI is powered by OpenSlice, an open-source prototype Operations Support System (OSS) built on TM Forum's Open Digital Architecture (ODA) principles. It provides extensive support for TMF Open APIs, enabling comprehensive Catalog Management, Ordering, and Inventory for Products, Services, and Resources. OpenSlice also integrates natively with leading technologies and resource controllers, including Kubernetes, ETSI MANO, LF Sylva, CAMARA, 3GPP CAPIF, and open-source monitoring stacks.

", + "CONNECT_WITH_US_HTML":"
", + "FOOTER_HTML":"
OpenSlice has received funding from various projects under European Programmes for research, technological development and demonstration. You may refer to our extensive ecosystem for further details.
OpenSlice by ETSI running OSL version 2025Q4 | Terms and Conditions | © 2026 on behalf of osl.etsi.org
" + } \ No newline at end of file diff --git a/kubernetes/helm/openslice/templates/_helpers.tpl b/kubernetes/helm/openslice/templates/_helpers.tpl index 89f9f71fba483f569751099ef78cdfb1da8a3f4c..b4dd9c5237e9ec2ccf588abe95978acf27875f48 100644 --- a/kubernetes/helm/openslice/templates/_helpers.tpl +++ b/kubernetes/helm/openslice/templates/_helpers.tpl @@ -60,3 +60,62 @@ Create the name of the service account to use {{- default "default" .Values.serviceAccount.name }} {{- end }} {{- end }} + +{{/* +Secrets +*/}} +{{- define "openslice.secrets.activemq" -}} +{{- if .Values.oscreds.activemq.existingSecret }} +{{- .Values.oscreds.activemq.existingSecret }} +{{- else }} +{{- include "openslice.fullname" . }}-artemis-secret +{{- end }} +{{- end }} + +{{- define "openslice.secrets.mysql" -}} +{{- if .Values.oscreds.mysql.existingSecret }} +{{- .Values.oscreds.mysql.existingSecret }} +{{- else }} +{{- include "openslice.fullname" . }}-mysql-secrets +{{- end }} +{{- end }} + +{{- define "openslice.secrets.keycloak.mysql" -}} +{{- if .Values.oscreds.mysql.keycloak.existingMySQLSecret }} +{{- .Values.oscreds.mysql.keycloak.existingMySQLSecret }} +{{- else }} +{{- include "openslice.fullname" . }}-mysql-keycloak-secrets +{{- end }} +{{- end }} + +{{- define "openslice.secrets.keycloak.admin" -}} +{{- if .Values.oscreds.mysql.keycloak.existingSecret }} +{{- .Values.oscreds.mysql.keycloak.existingSecret }} +{{- else }} +{{- include "openslice.fullname" . }}-keycloak-secret +{{- end }} +{{- end }} + +{{- define "openslice.secrets.portal.mysql" -}} +{{- if .Values.oscreds.mysql.portal.existingSecret }} +{{- .Values.oscreds.mysql.portal.existingSecret }} +{{- else }} +{{- include "openslice.fullname" . }}-mysql-portal-secrets +{{- end }} +{{- end }} + +{{- define "openslice.secrets.tmf.mysql" -}} +{{- if .Values.oscreds.mysql.tmf.existingSecret }} +{{- .Values.oscreds.mysql.tmf.existingSecret }} +{{- else }} +{{- include "openslice.fullname" . }}-mysql-tmf-secrets +{{- end }} +{{- end }} + +{{- define "openslice.secrets.metrico.mysql" -}} +{{- if .Values.oscreds.mysql.metrico.existingSecret }} +{{- .Values.oscreds.mysql.metrico.existingSecret }} +{{- else }} +{{- include "openslice.fullname" . }}-mysql-metrico-secrets +{{- end }} +{{- end }} diff --git a/kubernetes/helm/openslice/templates/artemis-secret.yaml b/kubernetes/helm/openslice/templates/artemis-secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..cceefc21fcb7f187ec9cbf98a5bc9f2d52aac86c --- /dev/null +++ b/kubernetes/helm/openslice/templates/artemis-secret.yaml @@ -0,0 +1,15 @@ +{{- if not .Values.oscreds.activemq.existingSecret -}} +apiVersion: v1 +kind: Secret +metadata: + namespace: {{ .Release.Namespace }} + labels: + app: {{ include "openslice.fullname" . }} + org.etsi.osl.service: mysql + chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- include "openslice.labels" . | nindent 4 }} + name: {{ include "openslice.fullname" . }}-artemis-secret +data: + username: {{ .Values.oscreds.activemq.user | b64enc }} + password: {{ .Values.oscreds.activemq.password | b64enc }} +{{- end -}} diff --git a/kubernetes/helm/openslice/templates/artemis.yaml b/kubernetes/helm/openslice/templates/artemis.yaml index 87c75ea00d59459c65d068fce3d7f8eb62fa71bc..17e18a021021d2440e53d69c4f2d3f44ce3f5ed1 100644 --- a/kubernetes/helm/openslice/templates/artemis.yaml +++ b/kubernetes/helm/openslice/templates/artemis.yaml @@ -28,6 +28,17 @@ spec: - image: "{{ .Values.image.artemis.repository }}:{{ .Values.image.artemis.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.artemis.pullPolicy | default "Always" }} name: {{ include "openslice.fullname" . }}-artemis + env: + - name: ARTEMIS_USER + valueFrom: + secretKeyRef: + name: {{ include "openslice.secrets.activemq" . }} + key: username + - name: ARTEMIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "openslice.secrets.activemq" . }} + key: password resources: {{- toYaml .Values.resources | nindent 12 }} ports: diff --git a/kubernetes/helm/openslice/templates/bugzilla.yaml b/kubernetes/helm/openslice/templates/bugzilla.yaml index d759a2554c42af2abf6e209f2207b92cfc9ef7cb..09323cfee26429bd49a6bde4c27fce625507ca92 100644 --- a/kubernetes/helm/openslice/templates/bugzilla.yaml +++ b/kubernetes/helm/openslice/templates/bugzilla.yaml @@ -31,11 +31,10 @@ spec: env: - name: SPRING_APPLICATION_JSON value: >- - { + { + "spring.config.import": "configtree:/etc/config/", "spring.activemq.brokerUrl": "tcp://{{ include "openslice.fullname" . }}-artemis:61616?jms.watchTopicAdvisories=false", - "spring.activemq.user": "{{ .Values.oscreds.activemq.user }}", - "spring.activemq.password": "{{ .Values.oscreds.activemq.password }}", - "bugzillaurl":"{{ .Values.bugzillaurl }}", + "bugzillaurl":"{{ .Values.bugzillaurl }}", "bugzillakey":"{{ .Values.bugzillakey }}", "main_operations_product":"{{ .Values.main_operations_product }}" } @@ -43,7 +42,20 @@ spec: {{- toYaml .Values.resources | nindent 12 }} ports: - containerPort: 13010 + volumeMounts: + - mountPath: "/etc/config/spring.activemq.user" + name: artemis-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.activemq.password" + name: artemis-secrets + subPath: password + readOnly: true restartPolicy: Always + volumes: + - name: artemis-secrets + secret: + secretName: {{ include "openslice.secrets.activemq" . }} --- apiVersion: v1 kind: Service diff --git a/kubernetes/helm/openslice/templates/centrallog.yaml b/kubernetes/helm/openslice/templates/centrallog.yaml index b8143fcd9f39869242c7192e96b1a55a08e94246..e61dc66710455d4606b7ccf9bfcb6ccd4c3df291 100644 --- a/kubernetes/helm/openslice/templates/centrallog.yaml +++ b/kubernetes/helm/openslice/templates/centrallog.yaml @@ -31,17 +31,29 @@ spec: env: - name: SPRING_APPLICATION_JSON value: >- - { + { + "spring.config.import": "configtree:/etc/config/", "spring.activemq.brokerUrl": "tcp://{{ include "openslice.fullname" . }}-artemis:61616?jms.watchTopicAdvisories=false", - "spring.activemq.user": "{{ .Values.oscreds.activemq.user }}", - "spring.activemq.password": "{{ .Values.oscreds.activemq.password }}", "centrallogurl": "{{ .Values.centrallogurl }}" } resources: {{- toYaml .Values.resources | nindent 12 }} ports: - containerPort: 13013 + volumeMounts: + - mountPath: "/etc/config/spring.activemq.user" + name: artemis-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.activemq.password" + name: artemis-secrets + subPath: password + readOnly: true restartPolicy: Always + volumes: + - name: artemis-secrets + secret: + secretName: {{ include "openslice.secrets.activemq" . }} --- apiVersion: v1 kind: Service diff --git a/kubernetes/helm/openslice/templates/cridge.yaml b/kubernetes/helm/openslice/templates/cridge.yaml index 10656390c474046f1bee83e9531b0cf87da57272..bcbf67400234034075e9b77575d111b22ea5cc7f 100644 --- a/kubernetes/helm/openslice/templates/cridge.yaml +++ b/kubernetes/helm/openslice/templates/cridge.yaml @@ -31,9 +31,8 @@ spec: - name: SPRING_APPLICATION_JSON value: >- { + "spring.config.import": "configtree:/etc/config/", "spring.activemq.brokerUrl": "tcp://{{ include "openslice.fullname" . }}-artemis:61616?jms.watchTopicAdvisories=false", - "spring.activemq.user": "{{ .Values.oscreds.activemq.user }}", - "spring.activemq.password": "{{ .Values.oscreds.activemq.password }}", "logging.level.org.springframework" : "{{ .Values.cridge.spring.logLevel | default "INFO" }}", "logging.level.org.etsi.osl.cridge" : "{{ .Values.cridge.logLevel | default "INFO" }}" } @@ -43,9 +42,20 @@ spec: - name: kubeconfig readOnly: true mountPath: /root/.kube + - mountPath: "/etc/config/spring.activemq.user" + name: artemis-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.activemq.password" + name: artemis-secrets + subPath: password + readOnly: true restartPolicy: Always volumes: - name: kubeconfig secret: secretName: {{ include "openslice.fullname" . }}-kubeconfig + - name: artemis-secrets + secret: + secretName: {{ include "openslice.secrets.activemq" . }} {{- end }} diff --git a/kubernetes/helm/openslice/templates/keycloak-secret.yaml b/kubernetes/helm/openslice/templates/keycloak-secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c6b7d4fe56ebd434dceaf087555d4bd04e1240c0 --- /dev/null +++ b/kubernetes/helm/openslice/templates/keycloak-secret.yaml @@ -0,0 +1,14 @@ +{{- if not .Values.oscreds.mysql.keycloak.existingSecret -}} +apiVersion: v1 +kind: Secret +metadata: + namespace: {{ .Release.Namespace }} + labels: + app: {{ include "openslice.fullname" . }} + org.etsi.osl.service: mysql + chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- include "openslice.labels" . | nindent 4 }} + name: {{ include "openslice.fullname" . }}-keycloak-secret +data: + admin-password: {{ .Values.oscreds.mysql.keycloak.adminpassword | b64enc }} +{{- end -}} diff --git a/kubernetes/helm/openslice/templates/keycloak.yaml b/kubernetes/helm/openslice/templates/keycloak.yaml index fca2bdbe8782e30adda9e4a54e3b0aa455f5a573..843f1dfc7013013cd083fc78f2798a7b6429233d 100644 --- a/kubernetes/helm/openslice/templates/keycloak.yaml +++ b/kubernetes/helm/openslice/templates/keycloak.yaml @@ -39,15 +39,27 @@ spec: - name: DB_ADDR value: {{ include "openslice.fullname" . }}-mysql - name: DB_DATABASE - value: {{ .Values.oscreds.mysql.keycloak.database }} + valueFrom: + secretKeyRef: + name: {{ include "openslice.secrets.keycloak.mysql" . }} + key: database - name: DB_PASSWORD - value: {{ .Values.oscreds.mysql.keycloak.password }} + valueFrom: + secretKeyRef: + name: {{ include "openslice.secrets.keycloak.mysql" . }} + key: password - name: DB_USER - value: {{ .Values.oscreds.mysql.keycloak.username }} + valueFrom: + secretKeyRef: + name: {{ include "openslice.secrets.keycloak.mysql" . }} + key: username - name: KEYCLOAK_USER value: admin - name: KEYCLOAK_PASSWORD - value: {{ .Values.oscreds.mysql.keycloak.adminpassword }} + valueFrom: + secretKeyRef: + name: {{ include "openslice.secrets.keycloak.admin" . }} + key: admin-password - name: JDBC_PARAMS value: useSSL=false - name: JAVA_OPTS diff --git a/kubernetes/helm/openslice/templates/manoclient.yaml b/kubernetes/helm/openslice/templates/manoclient.yaml index 064c0c18b043595834c087cdf909ba8a2111dcf8..c773eba011828aeb89e0738749909dbdfe3452be 100644 --- a/kubernetes/helm/openslice/templates/manoclient.yaml +++ b/kubernetes/helm/openslice/templates/manoclient.yaml @@ -32,16 +32,28 @@ spec: - name: SPRING_APPLICATION_JSON value: >- { + "spring.config.import": "configtree:/etc/config/", "spring.activemq.brokerUrl": "tcp://{{ include "openslice.fullname" . }}-artemis:61616?jms.watchTopicAdvisories=false", - "spring.activemq.user": "{{ .Values.oscreds.activemq.user }}", - "spring.activemq.password": "{{ .Values.oscreds.activemq.password }}", "logging.level.org.springframework" : "{{ .Values.manoclient.spring.logLevel | default "INFO" }}" } resources: {{- toYaml .Values.resources | nindent 12 }} ports: - containerPort: 13011 + volumeMounts: + - mountPath: "/etc/config/spring.activemq.user" + name: artemis-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.activemq.password" + name: artemis-secrets + subPath: password + readOnly: true restartPolicy: Always + volumes: + - name: artemis-secrets + secret: + secretName: {{ include "openslice.secrets.activemq" . }} --- apiVersion: v1 kind: Service diff --git a/kubernetes/helm/openslice/templates/mcp-backend.yaml b/kubernetes/helm/openslice/templates/mcp-backend.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b60eff66265e33b1880f6ebd4923d333a8353a86 --- /dev/null +++ b/kubernetes/helm/openslice/templates/mcp-backend.yaml @@ -0,0 +1,108 @@ +{{- if .Values.mcpbackend.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: {{ .Release.Namespace }} + labels: + app: {{ include "openslice.fullname" . }} + org.etsi.osl.service: mcpbackend + chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- include "openslice.labels" . | nindent 4 }} + name: {{ include "openslice.fullname" . }}-mcpbackend +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ include "openslice.fullname" . }} + org.etsi.osl.service: mcpbackend + {{- include "openslice.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + app: {{ include "openslice.fullname" . }} + org.etsi.osl.service: mcpbackend + {{- include "openslice.selectorLabels" . | nindent 8 }} + spec: + containers: + - name: {{ include "openslice.fullname" . }}-mcpbackend + image: "{{ .Values.image.mcpbackend.repository }}:{{ .Values.image.mcpbackend.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.mcpbackend.pullPolicy | default "Always" }} + env: + - name: SPRING_APPLICATION_JSON + value: >- + { + "origins":"{{ .Values.rooturl }}", + "spring.config.import": "configtree:/etc/config/", + "server.forward-headers-strategy":"FRAMEWORK" + } + - name: SERVER_PORT + value: "11880" + - name: SPRING_APPLICATION_NAME + value: "osl-mcp-backend" + - name: SPRING_AI_OLLAMA_BASE_URL + value: "{{ .Values.mcpbackend.spring.ai.ollama.apiUrl }}" + - name: SPRING_AI_OLLAMA_CHAT_MODEL + value: "{{ .Values.mcpbackend.spring.ai.ollama.model }}" + - name: SPRING_AI_OLLAMA_CHAT_TEMPERATURE + value: "{{ .Values.mcpbackend.spring.ai.ollama.temperature }}" + - name: SPRING_AI_CHAT_SYSTEM_PROMPT + value: "{{ .Values.mcpbackend.spring.ai.chat.systemPrompt }}" + - name: SPRING_AI_CHAT_MAX_MESSAGES + value: "{{ .Values.mcpbackend.spring.ai.chat.maxMessages }}" + - name: SPRING_AI_MCP_CLIENT_TYPE + value: "SYNC" + - name: SPRING_AI_MCP_CLIENT_STREAMABLE_HTTP_CONNECTIONS_OPENSLICE_SERVER_URL + value: "http://{{ include "openslice.fullname" . }}-mcpserver:13015/sse" + - name: SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI + value: "{{ .Values.rooturl }}/auth/realms/openslice" + - name: SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_ISSUER_URI + value: "{{ .Values.rooturl }}/auth/realms/openslice" + - name: SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_CLIENT_ID + value: "osapiWebClientId" + - name: SPRING_ACTIVEMQ_BROKER_URL + value: "tcp://{{ include "openslice.fullname" . }}-artemis:61616?jms.watchTopicAdvisories=false" + - name: LOGGING_LEVEL_ROOT + value: "{{ .Values.mcpbackend.logLevelRoot | default "INFO" }}" + - name: LOGGING_LEVEL_OSL + value: "{{ .Values.mcpbackend.logLevelOSL | default "INFO" }}" + - name: LOGGING_LEVEL_SPRING_AI + value: "{{ .Values.mcpbackend.spring.logLevel | default "INFO" }}" + ports: + - containerPort: 11880 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - mountPath: "/etc/config/spring.activemq.user" + name: artemis-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.activemq.password" + name: artemis-secrets + subPath: password + readOnly: true + restartPolicy: Always + volumes: + - name: artemis-secrets + secret: + secretName: {{ include "openslice.secrets.activemq" . }} +--- +apiVersion: v1 +kind: Service +metadata: + namespace: {{ .Release.Namespace }} + labels: + app: {{ include "openslice.fullname" . }} + org.etsi.osl.service: mcpbackend + chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- include "openslice.labels" . | nindent 4 }} + name: {{ include "openslice.fullname" . }}-mcpbackend +spec: + ports: + - name: "11880" + port: 11880 + targetPort: 11880 + selector: + app: {{ include "openslice.fullname" . }} + org.etsi.osl.service: mcpbackend + {{- include "openslice.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/kubernetes/helm/openslice/templates/mcp-server-ingress.yaml.yaml b/kubernetes/helm/openslice/templates/mcp-server-ingress.yaml similarity index 100% rename from kubernetes/helm/openslice/templates/mcp-server-ingress.yaml.yaml rename to kubernetes/helm/openslice/templates/mcp-server-ingress.yaml diff --git a/kubernetes/helm/openslice/templates/mcp-server.yaml b/kubernetes/helm/openslice/templates/mcp-server.yaml index 942f9a9a170321dff7bfe69224f30655f25c15e3..12f6bfe1d9065b9933730f335c5c567426cdc200 100644 --- a/kubernetes/helm/openslice/templates/mcp-server.yaml +++ b/kubernetes/helm/openslice/templates/mcp-server.yaml @@ -31,28 +31,48 @@ spec: - name: SPRING_APPLICATION_JSON value: >- { - "spring.datasource.url": "jdbc:mysql://{{ include "openslice.fullname" . }}-mysql/osdb?createDatabaseIfNotExist=true", - "spring.datasource.username": "{{ .Values.oscreds.mysql.username }}", - "spring.datasource.password": "{{ .Values.oscreds.mysql.password }}", + "spring.config.import": "configtree:/etc/config/", + "spring.datasource.url": "jdbc:mysql://{{ include "openslice.fullname" . }}-mysql/{{ .Values.oscreds.mysql.portal.database }}", "spring-addons.issuers[0].uri": "{{ .Values.rooturl }}/auth/realms/openslice", "spring-addons.issuers[0].username-json-path":"$.preferred_username", "spring-addons.issuers[0].claims[0].jsonPath":"$.realm_access.roles", "spring-addons.issuers[0].claims[1].jsonPath":"$.resource_access.*.roles", "spring.security.oauth2.resourceserver.jwt.issuer-uri": "{{ .Values.rooturl }}/auth/realms/openslice", "springdoc.oAuthFlow.authorizationUrl": "{{ .Values.rooturl }}/auth/realms/openslice/protocol/openid-connect/auth", - "springdoc.oAuthFlow.tokenUrl": "{{ .Values.rooturl }}/auth/realms/openslice/protocol/openid-connect/token", - "springdoc.oauth.client-id": "osapiWebClientId", - "springdoc.oauth.clientsecret": "{{ .Values.mcpserver.springdoc.clientSecret }}", + "springdoc.oAuthFlow.tokenUrl": "{{ .Values.rooturl }}/auth/realms/openslice/protocol/openid-connect/token", + "springdoc.oauth.client-id": "osapiWebClientId", "spring.activemq.brokerUrl": "tcp://{{ include "openslice.fullname" . }}-artemis:61616?jms.watchTopicAdvisories=false", - "spring.activemq.user": "{{ .Values.oscreds.activemq.user }}", - "spring.activemq.password": "{{ .Values.oscreds.activemq.password }}", "logging.level.org.springframework": "{{ .Values.mcpserver.spring.logLevel | default "INFO" }}" } ports: - containerPort: 13015 resources: {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - mountPath: "/etc/config/spring.datasource.username" + name: mysql-portal-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.datasource.password" + name: mysql-portal-secrets + subPath: password + readOnly: true + - mountPath: "/etc/config/spring.activemq.user" + name: artemis-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.activemq.password" + name: artemis-secrets + subPath: password + readOnly: true restartPolicy: Always + volumes: + - name: artemis-secrets + secret: + secretName: {{ include "openslice.secrets.activemq" . }} + - name: mysql-portal-secrets + secret: + secretName: {{ include "openslice.secrets.portal.mysql" . }} --- apiVersion: v1 kind: Service diff --git a/kubernetes/helm/openslice/templates/metrico.yaml b/kubernetes/helm/openslice/templates/metrico.yaml index 620ca0aa2146d38585535fbad658d42536ec7a53..d894b500b1d31b52c59c0b28058ed017af6a4ad3 100644 --- a/kubernetes/helm/openslice/templates/metrico.yaml +++ b/kubernetes/helm/openslice/templates/metrico.yaml @@ -33,14 +33,35 @@ spec: - name: SPRING_APPLICATION_JSON value: >- { - "spring.datasource.url": "jdbc:mysql://{{ include "openslice.fullname" . }}-mysql/metricodb?createDatabaseIfNotExist=true", - "spring.datasource.username": "{{ .Values.oscreds.mysql.username }}", - "spring.datasource.password": "{{ .Values.oscreds.mysql.password }}", - "spring.activemq.brokerUrl": "tcp://{{ include "openslice.fullname" . }}-artemis:61616?jms.watchTopicAdvisories=false", - "spring.activemq.user": "{{ .Values.oscreds.activemq.user }}", - "spring.activemq.password": "{{ .Values.oscreds.activemq.password }}", + "spring.config.import": "configtree:/etc/config/", + "spring.datasource.url": "jdbc:mysql://{{ include "openslice.fullname" . }}-mysql/{{ .Values.oscreds.mysql.metrico.database }}", + "spring.activemq.brokerUrl": "tcp://{{ include "openslice.fullname" . }}-artemis:61616?jms.watchTopicAdvisories=false", "logging.level.org.springframework" : "{{ .Values.metrico.spring.logLevel | default "INFO" }}", "logging.level.org.etsi.osl.cridge" : "{{ .Values.metrico.logLevel | default "INFO" }}" } + volumeMounts: + - mountPath: "/etc/config/spring.datasource.username" + name: mysql-metrico-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.datasource.password" + name: mysql-metrico-secrets + subPath: password + readOnly: true + - mountPath: "/etc/config/spring.activemq.user" + name: artemis-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.activemq.password" + name: artemis-secrets + subPath: password + readOnly: true restartPolicy: Always + volumes: + - name: artemis-secrets + secret: + secretName: {{ include "openslice.secrets.activemq" . }} + - name: mysql-metrico-secrets + secret: + secretName: {{ include "openslice.secrets.metrico.mysql" . }} {{- end }} diff --git a/kubernetes/helm/openslice/templates/mysql-config.yaml b/kubernetes/helm/openslice/templates/mysql-config.yaml index 0de0e5277807c43e82193fa44c53a07e386b9470..5a29569d4a6ea22e2095b8db0b02da5c0085747d 100644 --- a/kubernetes/helm/openslice/templates/mysql-config.yaml +++ b/kubernetes/helm/openslice/templates/mysql-config.yaml @@ -7,7 +7,7 @@ metadata: org.etsi.osl.service: mysql chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" {{- include "openslice.labels" . | nindent 4 }} - name: {{ include "openslice.fullname" . }}-mysql-initdb-config + name: {{ include "openslice.fullname" . }}-mysql-init-config data: - 01-databases.sql: | - {{- tpl (.Files.Get "files/mysql-init/01-databases.sql") . | nindent 4 }} + entrypoint.sh: | + {{- .Files.Get "files/mysql-init/entrypoint.sh" | nindent 4 }} diff --git a/kubernetes/helm/openslice/templates/mysql-keycloak-secret.yaml b/kubernetes/helm/openslice/templates/mysql-keycloak-secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3f3035ca0a26e3563613219925462e643f7562d7 --- /dev/null +++ b/kubernetes/helm/openslice/templates/mysql-keycloak-secret.yaml @@ -0,0 +1,16 @@ +{{- if not .Values.oscreds.mysql.keycloak.existingMySQLSecret -}} +apiVersion: v1 +kind: Secret +metadata: + namespace: {{ .Release.Namespace }} + labels: + app: {{ include "openslice.fullname" . }} + org.etsi.osl.service: mysql + chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- include "openslice.labels" . | nindent 4 }} + name: {{ include "openslice.fullname" . }}-mysql-keycloak-secrets +data: + username: {{ .Values.oscreds.mysql.keycloak.username | default "keycloak" | b64enc }} + password: {{ .Values.oscreds.mysql.keycloak.password | default "password" | b64enc }} + database: {{ .Values.oscreds.mysql.keycloak.database | default "keycloak" | b64enc }} +{{- end -}} diff --git a/kubernetes/helm/openslice/templates/mysql-metrico-secret.yaml b/kubernetes/helm/openslice/templates/mysql-metrico-secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4685b05b1a4ef466b6480ac9563d645b210537b1 --- /dev/null +++ b/kubernetes/helm/openslice/templates/mysql-metrico-secret.yaml @@ -0,0 +1,16 @@ +{{- if not .Values.oscreds.mysql.metrico.existingSecret -}} +apiVersion: v1 +kind: Secret +metadata: + namespace: {{ .Release.Namespace }} + labels: + app: {{ include "openslice.fullname" . }} + org.etsi.osl.service: mysql + chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- include "openslice.labels" . | nindent 4 }} + name: {{ include "openslice.fullname" . }}-mysql-metrico-secrets +data: + username: {{ .Values.oscreds.mysql.metrico.username | default "metricouser" | b64enc }} + password: {{ .Values.oscreds.mysql.metrico.password | default "12345" | b64enc }} + database: {{ .Values.oscreds.mysql.metrico.database | default "metricodb" | b64enc }} +{{- end -}} diff --git a/kubernetes/helm/openslice/templates/mysql-portal-secret.yaml b/kubernetes/helm/openslice/templates/mysql-portal-secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..99afd54fe6b11c20cc50ae6e0b92e6897af67e28 --- /dev/null +++ b/kubernetes/helm/openslice/templates/mysql-portal-secret.yaml @@ -0,0 +1,16 @@ +{{- if not .Values.oscreds.mysql.portal.existingSecret -}} +apiVersion: v1 +kind: Secret +metadata: + namespace: {{ .Release.Namespace }} + labels: + app: {{ include "openslice.fullname" . }} + org.etsi.osl.service: mysql + chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- include "openslice.labels" . | nindent 4 }} + name: {{ include "openslice.fullname" . }}-mysql-portal-secrets +data: + username: {{ .Values.oscreds.mysql.portal.username | default "portaluser" | b64enc }} + password: {{ .Values.oscreds.mysql.portal.password | default "12345" | b64enc }} + database: {{ .Values.oscreds.mysql.portal.database | default "osdb" | b64enc }} +{{- end -}} diff --git a/kubernetes/helm/openslice/templates/mysql-secret.yaml b/kubernetes/helm/openslice/templates/mysql-secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..9db23d40e2b68ef60ba379a216024f1c581f1db1 --- /dev/null +++ b/kubernetes/helm/openslice/templates/mysql-secret.yaml @@ -0,0 +1,14 @@ +{{- if not .Values.oscreds.mysql.existingSecret -}} +apiVersion: v1 +kind: Secret +metadata: + namespace: {{ .Release.Namespace }} + labels: + app: {{ include "openslice.fullname" . }} + org.etsi.osl.service: mysql + chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- include "openslice.labels" . | nindent 4 }} + name: {{ include "openslice.fullname" . }}-mysql-secrets +data: + root-password: {{ .Values.oscreds.mysql.password | default "letmein" | b64enc }} +{{- end -}} diff --git a/kubernetes/helm/openslice/templates/mysql-tmf-secret.yaml b/kubernetes/helm/openslice/templates/mysql-tmf-secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8d5a50c696e63f664cda71ef4ac4c027d96a3bdb --- /dev/null +++ b/kubernetes/helm/openslice/templates/mysql-tmf-secret.yaml @@ -0,0 +1,16 @@ +{{- if not .Values.oscreds.mysql.tmf.existingSecret -}} +apiVersion: v1 +kind: Secret +metadata: + namespace: {{ .Release.Namespace }} + labels: + app: {{ include "openslice.fullname" . }} + org.etsi.osl.service: mysql + chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" + {{- include "openslice.labels" . | nindent 4 }} + name: {{ include "openslice.fullname" . }}-mysql-tmf-secrets +data: + username: {{ .Values.oscreds.mysql.tmf.username | default "tmfuser" | b64enc }} + password: {{ .Values.oscreds.mysql.tmf.password | default "12345" | b64enc }} + database: {{ .Values.oscreds.mysql.tmf.database | default "ostmfdb" | b64enc }} +{{- end -}} diff --git a/kubernetes/helm/openslice/templates/mysql.yaml b/kubernetes/helm/openslice/templates/mysql.yaml index b69a3f1e8cd3ecf222ed5aaa21f44feb52d2d950..aebd6fb8e6626306bf3293b7edd7fb178f58e8f1 100644 --- a/kubernetes/helm/openslice/templates/mysql.yaml +++ b/kubernetes/helm/openslice/templates/mysql.yaml @@ -35,26 +35,48 @@ spec: - name: MYSQL_ROOT_HOST value: "%" - name: MYSQL_ROOT_PASSWORD - value: {{ .Values.oscreds.mysql.password | default "letmein" }} - - name: MYSQL_DATABASE - value: {{ .Values.oscreds.mysql.openslicedb | default "osdb" }} - - name: MYSQL_USER - value: {{ .Values.oscreds.mysql.portal.username | default "portaluser" }} - - name: MYSQL_PASSWORD - value: "{{ .Values.oscreds.mysql.portal.password | default 12345 }}" + valueFrom: + secretKeyRef: + name: {{ include "openslice.secrets.mysql" . }} + key: root-password resources: {{- toYaml .Values.resources | nindent 12 }} ports: - containerPort: 3306 + lifecycle: + postStart: + exec: + command: ["/init/entrypoint.sh"] volumeMounts: - mountPath: /var/lib/mysql name: mysql-portal-claim0 - - mountPath: /docker-entrypoint-initdb.d - name: mysql-initdb + - mountPath: /init + name: mysql-init + - mountPath: "/var/run/secrets/mysql" + readOnly: true + name: mysql-secrets + - mountPath: "/var/run/secrets/portal" + readOnly: true + name: mysql-portal-secrets + - mountPath: "/var/run/secrets/tmf" + readOnly: true + name: mysql-tmf-secrets + - mountPath: "/var/run/secrets/keycloak" + readOnly: true + name: mysql-keycloak-secrets + - mountPath: "/var/run/secrets/metrico" + readOnly: true + name: mysql-metrico-secrets + livenessProbe: + exec: + command: ["sh", "-c", "mysqladmin ping -p\"$MYSQL_ROOT_PASSWORD\""] + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 readinessProbe: exec: # Check we can execute queries over TCP (skip-networking is off). - command: ["mysql", "-h", "127.0.0.1", "-u", "{{ .Values.oscreds.mysql.username | default "root" }}", "-p{{ .Values.oscreds.mysql.password | default "letmein" }}", "-e", "SELECT 1"] + command: ["sh", "-c", "mysql -p\"$MYSQL_ROOT_PASSWORD\" -h 127.0.0.1 -e 'SELECT 1'"] initialDelaySeconds: 5 periodSeconds: 2 timeoutSeconds: 1 @@ -63,9 +85,25 @@ spec: - name: mysql-portal-claim0 persistentVolumeClaim: claimName: {{ include "openslice.fullname" . }}-mysql-portal-claim0 - - name: mysql-initdb + - name: mysql-init configMap: - name: {{ include "openslice.fullname" . }}-mysql-initdb-config + name: {{ include "openslice.fullname" . }}-mysql-init-config + defaultMode: 0755 + - name: mysql-secrets + secret: + secretName: {{ include "openslice.secrets.mysql" . }} + - name: mysql-portal-secrets + secret: + secretName: {{ include "openslice.secrets.portal.mysql" . }} + - name: mysql-tmf-secrets + secret: + secretName: {{ include "openslice.secrets.tmf.mysql" . }} + - name: mysql-keycloak-secrets + secret: + secretName: {{ include "openslice.secrets.keycloak.mysql" . }} + - name: mysql-metrico-secrets + secret: + secretName: {{ include "openslice.secrets.metrico.mysql" . }} --- apiVersion: v1 kind: Service diff --git a/kubernetes/helm/openslice/templates/oasapi.yaml b/kubernetes/helm/openslice/templates/oasapi.yaml index bf78b5dd478c19f009fddd599d6537fb7b667c66..427e2ff01f48c027ee7d3611945067fff69141dc 100644 --- a/kubernetes/helm/openslice/templates/oasapi.yaml +++ b/kubernetes/helm/openslice/templates/oasapi.yaml @@ -28,7 +28,7 @@ spec: - name: init-keycloak image: busybox:1.28 command: ['sh', '-c', "until nslookup {{ include "openslice.fullname" . }}-keycloak; do echo waiting for keycloak; sleep 2; done"] - - name: init-mysql-portal + - name: init-mysql image: busybox:1.28 command: ['sh', '-c', "until nslookup {{ include "openslice.fullname" . }}-mysql; do echo waiting for mysql; sleep 2; done"] hostNetwork: {{ .Values.hostNetwork }} @@ -36,26 +36,22 @@ spec: - image: "{{ .Values.image.oasapi.repository }}:{{ .Values.image.oasapi.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.oasapi.pullPolicy | default "Always" }} name: {{ .Release.Name }}-oasapi - env: + env: - name: SPRING_APPLICATION_JSON value: >- { - "origins":"{{ .Values.rooturl }}", - "spring.datasource.url": "jdbc:mysql://{{ include "openslice.fullname" . }}-mysql/ostmfdb?createDatabaseIfNotExist=true&useUnicode=true&nullCatalogMeansCurrent=true&characterEncoding=utf8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC", - "spring.datasource.username": "{{ .Values.oscreds.mysql.username }}", - "spring.datasource.password": "{{ .Values.oscreds.mysql.password }}", - "spring-addons.issuers[0].uri": "{{ .Values.rooturl }}/auth/realms/openslice", + "origins":"{{ .Values.rooturl }}", + "spring.config.import": "configtree:/etc/config/", + "spring.datasource.url": "jdbc:mysql://{{ include "openslice.fullname" . }}-mysql/{{ .Values.oscreds.mysql.tmf.database }}", + "spring-addons.issuers[0].uri": "{{ .Values.rooturl }}/auth/realms/openslice", "spring-addons.issuers[0].username-json-path":"$.preferred_username", "spring-addons.issuers[0].claims[0].jsonPath":"$.realm_access.roles", "spring-addons.issuers[0].claims[1].jsonPath":"$.resource_access.*.roles", "spring.security.oauth2.resourceserver.jwt.issuer-uri": "{{ .Values.rooturl }}/auth/realms/openslice", "springdoc.oAuthFlow.authorizationUrl": "{{ .Values.rooturl }}/auth/realms/openslice/protocol/openid-connect/auth", - "springdoc.oAuthFlow.tokenUrl": "{{ .Values.rooturl }}/auth/realms/openslice/protocol/openid-connect/token", - "springdoc.oauth.client-id" : "osapiWebClientId", - "springdoc.oauth.clientsecret" : "{{ .Values.spring.oauthClientSecret }}", + "springdoc.oAuthFlow.tokenUrl": "{{ .Values.rooturl }}/auth/realms/openslice/protocol/openid-connect/token", + "springdoc.oauth.client-id": "osapiWebClientId", "spring.activemq.brokerUrl": "tcp://{{ include "openslice.fullname" . }}-artemis:61616?jms.watchTopicAdvisories=false", - "spring.activemq.user": "{{ .Values.oscreds.activemq.user }}", - "spring.activemq.password": "{{ .Values.oscreds.activemq.password }}", "logging.level.org.springframework" : "{{ .Values.oasapi.spring.logLevel | default "INFO" }}", "server.forward-headers-strategy":"FRAMEWORK" } @@ -67,7 +63,31 @@ spec: httpGet: path: /oas-api/swagger-ui/index.html port: 13101 + volumeMounts: + - mountPath: "/etc/config/spring.datasource.username" + name: mysql-tmf-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.datasource.password" + name: mysql-tmf-secrets + subPath: password + readOnly: true + - mountPath: "/etc/config/spring.activemq.user" + name: artemis-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.activemq.password" + name: artemis-secrets + subPath: password + readOnly: true restartPolicy: Always + volumes: + - name: artemis-secrets + secret: + secretName: {{ include "openslice.secrets.activemq" . }} + - name: mysql-tmf-secrets + secret: + secretName: {{ include "openslice.secrets.tmf.mysql" . }} --- apiVersion: v1 kind: Service diff --git a/kubernetes/helm/openslice/templates/osom.yaml b/kubernetes/helm/openslice/templates/osom.yaml index 14c8d2d2cbae36b462156a9292e5582506a388a8..31a8ab95c6eba40903add06dbadd8b37a23b94f7 100644 --- a/kubernetes/helm/openslice/templates/osom.yaml +++ b/kubernetes/helm/openslice/templates/osom.yaml @@ -31,18 +31,30 @@ spec: env: - name: SPRING_APPLICATION_JSON value: >- - { + { + "spring.config.import": "configtree:/etc/config/", "spring.datasource.url" : "{{ .Values.osom.spring.datasource.url | default "jdbc:h2:/tmp/tempdb;DB_CLOSE_DELAY=-1" }}", "spring.activemq.brokerUrl": "tcp://{{ include "openslice.fullname" . }}-artemis:61616?jms.watchTopicAdvisories=false", - "spring.activemq.user": "{{ .Values.oscreds.activemq.user }}", - "spring.activemq.password": "{{ .Values.oscreds.activemq.password }}", "logging.level.org.springframework" : "{{ .Values.osom.spring.logLevel | default "INFO" }}" } resources: {{- toYaml .Values.resources | nindent 12 }} ports: - containerPort: 13100 + volumeMounts: + - mountPath: "/etc/config/spring.activemq.user" + name: artemis-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.activemq.password" + name: artemis-secrets + subPath: password + readOnly: true restartPolicy: Always + volumes: + - name: artemis-secrets + secret: + secretName: {{ include "openslice.secrets.activemq" . }} --- apiVersion: v1 kind: Service diff --git a/kubernetes/helm/openslice/templates/osportalapi.yaml b/kubernetes/helm/openslice/templates/osportalapi.yaml index 6df11d4899aec82bc2f40444c8721ee57e94edce..5612e67194092a15bc33502c9b59aed5cf8d14e7 100644 --- a/kubernetes/helm/openslice/templates/osportalapi.yaml +++ b/kubernetes/helm/openslice/templates/osportalapi.yaml @@ -30,7 +30,7 @@ spec: - name: init-keycloak image: busybox:1.28 command: ['sh', '-c', "until nslookup {{ include "openslice.fullname" . }}-keycloak; do echo waiting for keycloak; sleep 2; done"] - - name: init-mysql-portal + - name: init-mysql image: busybox:1.28 command: ['sh', '-c', "until nslookup {{ include "openslice.fullname" . }}-mysql; do echo waiting for mysql; sleep 2; done"] containers: @@ -42,9 +42,8 @@ spec: value: >- { "origins":"{{ .Values.rooturl }}", - "spring.datasource.url": "jdbc:mysql://{{ include "openslice.fullname" . }}-mysql/osdb?createDatabaseIfNotExist=true", - "spring.datasource.username": "{{ .Values.oscreds.mysql.username }}", - "spring.datasource.password": "{{ .Values.oscreds.mysql.password }}", + "spring.config.import": "configtree:/etc/config/", + "spring.datasource.url": "jdbc:mysql://{{ include "openslice.fullname" . }}-mysql/{{ .Values.oscreds.mysql.portal.database }}", "spring-addons.issuers[0].uri": "{{ .Values.rooturl }}/auth/realms/openslice", "spring-addons.issuers[0].username-json-path":"$.preferred_username", "spring-addons.issuers[0].claims[0].jsonPath":"$.realm_access.roles", @@ -52,11 +51,8 @@ spec: "spring.security.oauth2.resourceserver.jwt.issuer-uri": "{{ .Values.rooturl }}/auth/realms/openslice", "springdoc.oAuthFlow.authorizationUrl": "{{ .Values.rooturl }}/auth/realms/openslice/protocol/openid-connect/auth", "springdoc.oAuthFlow.tokenUrl": "{{ .Values.rooturl }}/auth/realms/openslice/protocol/openid-connect/token", - "springdoc.oauth.client-id" : "osapiWebClientId", - "springdoc.oauth.clientsecret" : "{{ .Values.spring.oauthClientSecret }}", + "springdoc.oauth.client-id": "osapiWebClientId", "spring.activemq.brokerUrl": "tcp://{{ include "openslice.fullname" . }}-artemis:61616?jms.watchTopicAdvisories=false", - "spring.activemq.user": "{{ .Values.oscreds.activemq.user }}", - "spring.activemq.password": "{{ .Values.oscreds.activemq.password }}", "logging.level.org.springframework" : "{{ .Values.portalapi.spring.logLevel | default "INFO" }}", "logging.level.org.etsi.osl.portal.api": "{{ .Values.portalapi.logLevel | default "INFO" }}", "server.forward-headers-strategy":"FRAMEWORK" @@ -68,11 +64,33 @@ spec: volumeMounts: - name: osportalapi-claim0 mountPath: /root + - mountPath: "/etc/config/spring.datasource.username" + name: mysql-portal-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.datasource.password" + name: mysql-portal-secrets + subPath: password + readOnly: true + - mountPath: "/etc/config/spring.activemq.user" + name: artemis-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.activemq.password" + name: artemis-secrets + subPath: password + readOnly: true restartPolicy: Always volumes: - name: osportalapi-claim0 persistentVolumeClaim: claimName: {{ include "openslice.fullname" . }}-osportalapi-claim0 + - name: artemis-secrets + secret: + secretName: {{ include "openslice.secrets.activemq" . }} + - name: mysql-portal-secrets + secret: + secretName: {{ include "openslice.secrets.portal.mysql" . }} --- apiVersion: v1 kind: Service diff --git a/kubernetes/helm/openslice/templates/osscapi.yaml b/kubernetes/helm/openslice/templates/osscapi.yaml index 758d5194bba9efd07fe9e9b5dcdcb91a17611667..ab1b72d562aae2658c01c10d39c7db14e6a0b457 100644 --- a/kubernetes/helm/openslice/templates/osscapi.yaml +++ b/kubernetes/helm/openslice/templates/osscapi.yaml @@ -29,7 +29,7 @@ spec: - name: init-keycloak image: busybox:1.28 command: ['sh', '-c', "until nslookup {{ include "openslice.fullname" . }}-keycloak; do echo waiting for keycloak; sleep 2; done"] - - name: init-mysql-portal + - name: init-mysql image: busybox:1.28 command: ['sh', '-c', "until nslookup {{ include "openslice.fullname" . }}-mysql; do echo waiting for mysql; sleep 2; done"] containers: @@ -41,9 +41,8 @@ spec: value: >- { "origins":"{{ .Values.rooturl }}", - "spring.datasource.url": "jdbc:mysql://{{ include "openslice.fullname" . }}-mysql/osdb?createDatabaseIfNotExist=true", - "spring.datasource.username": "{{ .Values.oscreds.mysql.username }}", - "spring.datasource.password": "{{ .Values.oscreds.mysql.password }}", + "spring.config.import": "configtree:/etc/config/", + "spring.datasource.url": "jdbc:mysql://{{ include "openslice.fullname" . }}-mysql/{{ .Values.oscreds.mysql.tmf.database }}", "spring-addons.issuers[0].uri":"{{ .Values.rooturl }}/auth/realms/openslice", "spring-addons.issuers[0].username-json-path":"$.preferred_username", "spring-addons.issuers[0].claims[0].jsonPath":"$.realm_access.roles", @@ -52,11 +51,8 @@ spec: "spring.security.oauth2.resourceserver.jwt.jwk-set-uri":"{{ .Values.rooturl }}/auth/realms/openslice/.well-known/openid-configuration", "springdoc.oAuthFlow.authorizationUrl":"{{ .Values.rooturl }}/auth/realms/openslice/protocol/openid-connect/auth", "springdoc.oAuthFlow.tokenUrl":"{{ .Values.rooturl }}/auth/realms/openslice/protocol/openid-connect/token", - "springdoc.oauth.client-id":"osapiWebClientId", - "springdoc.oauth.clientsecret" : "{{ .Values.spring.oauthClientSecret }}", + "springdoc.oauth.client-id": "osapiWebClientId", "spring.activemq.brokerUrl": "tcp://{{ include "openslice.fullname" . }}-artemis:61616?jms.watchTopicAdvisories=false", - "spring.activemq.user": "{{ .Values.oscreds.activemq.user }}", - "spring.activemq.password": "{{ .Values.oscreds.activemq.password }}", "logging.level.org.springframework": "{{ .Values.osscapi.spring.logLevel | default "INFO" }}", "kroki.serverurl":"{{ .Values.rooturl }}/kroki", "server.forward-headers-strategy":"FRAMEWORK" @@ -68,6 +64,22 @@ spec: volumeMounts: - mountPath: /root name: osscapi-claim0 + - mountPath: "/etc/config/spring.datasource.username" + name: mysql-tmf-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.datasource.password" + name: mysql-tmf-secrets + subPath: password + readOnly: true + - mountPath: "/etc/config/spring.activemq.user" + name: artemis-secrets + subPath: username + readOnly: true + - mountPath: "/etc/config/spring.activemq.password" + name: artemis-secrets + subPath: password + readOnly: true readinessProbe: httpGet: path: /tmf-api/serviceCatalogManagement/v4/serviceCatalog @@ -77,6 +89,12 @@ spec: - name: osscapi-claim0 persistentVolumeClaim: claimName: {{ include "openslice.fullname" . }}-osscapi-claim0 + - name: artemis-secrets + secret: + secretName: {{ include "openslice.secrets.activemq" . }} + - name: mysql-tmf-secrets + secret: + secretName: {{ include "openslice.secrets.tmf.mysql" . }} --- apiVersion: v1 kind: Service diff --git a/kubernetes/helm/openslice/values.yaml b/kubernetes/helm/openslice/values.yaml index cc86020d7d3eb3c0d9084c177ab5dc911e7e16c7..53e849d97e8160d25a1b940b886f4591ad2c0a6d 100644 --- a/kubernetes/helm/openslice/values.yaml +++ b/kubernetes/helm/openslice/values.yaml @@ -1,4 +1,4 @@ -# Default values for openslice. +# Default values for OpenSlice. # This is a YAML-formatted file. # Declare variables to be passed into your templates. @@ -90,6 +90,11 @@ image: # Overrides the image tag whose default is the chart appVersion. tag: latest pullPolicy: Always + mcpbackend: + repository: labs.etsi.org:5050/osl/code/org.etsi.osl.mcp.backend + # Overrides the image tag whose default is the chart appVersion. + tag: latest + pullPolicy: Always bugzillaurl: example.com:443/bugzilla bugzillakey: VH2Vw0iI5aYgALFFzVDWqhACwt6Hu3bXla9kSC1Z @@ -99,24 +104,79 @@ rooturl: ~ # This is the ingress LB IP or domain - ex. http://openslice.com:port oscreds: activemq: + # The name of an existing secret to use for the activemq broker. + # + # The secret requires the following keys: + # - `username` the broker user + # - `password` the broker password + existingSecret: "" + user: artemis password: artemis mysql: - username: root + # The name of an existing secret to use for the mysql root user. + # + # The secret requires the following keys: + # - `root-password` containing the mysql root password. + existingSecret: "" + password: letmein - openslicedb: osdb - keycloak: + + keycloak: + # The name of an existing secret to use for the mysql keycloak user. + # + # The secret requires the following keys: + # - `username` the database user + # - `password` the database user's password + # - `database` the database to use for keycloak + existingMySQLSecret: "" + + # The name of an existing secret to use for keycloak. + # + # The secret requires the following keys: + # - `admin-password` the adminstrator password for keycloak + existingSecret: "" + database: keycloak username: keycloak password: password adminpassword: Pa55w0rd + tmf: + # The name of an existing secret to use for the tmf portal user. + # + # The secret requires the following keys: + # - `username` the database user + # - `password` the database user's password + # - `database` the database to use for the tmf apis + existingSecret: "" + + database: ostmfdb + username: tmfuser + password: "12345" portal: + # The name of an existing secret to use for the mysql portal user. + # + # The secret requires the following keys: + # - `username` the database user + # - `password` the database user's password + # - `database` the database to use for the portal + existingSecret: "" + database: osdb username: portaluser - password: 12345 + password: "12345" + metrico: + # The name of an existing secret to use for the mysql metrico user. + # + # The secret requires the following keys: + # - `username` the database user + # - `password` the database user's password + # - `database` the database to use for metrico + existingSecret: "" -spring: - oauthClientSecret: secret + database: metricodb + username: metricouser + password: "12345" mysql: storage: 10Gi @@ -161,11 +221,24 @@ osscapi: mcpserver: enabled: true - springdoc: - clientSecret: secret spring: logLevel: INFO +mcpbackend: + enabled: true + logLevelRoot: INFO + logLevelOSL: INFO + spring: + logLevel: INFO + ai: # AI Configuration + ollama: + model: "gtp-oss:20b" # Change the used model here + temperature: 0.5 + apiUrl: "http://ollama:11434" # Change the Ollama API here + chat: + systemPrompt: "You are an OpenSlice AI Assistant." # Customize your initial Assistant prompt + maxMessages: 100 # Maximum number of messages to keep in context + # Storage class to be used for provisioning. Default is manual # storageClass: ~ @@ -225,6 +298,9 @@ ingress: - path: "/" service: "tmfweb" port: 80 + - path: "/ask" + service: "mcpbackend" + port: 11880 annotations: {} diff --git a/kubernetes/observability/README.md b/kubernetes/observability/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d0c1635452d61bd9cb50443e28c2dbaf152adbb1 --- /dev/null +++ b/kubernetes/observability/README.md @@ -0,0 +1,24 @@ +# Openslice Pod Metrics and Logs Dashboard (Grafana) + +A dashboard to visualize Kubernetes pod metrics and logs. + +## Prerequisites + +- **Grafana** + A running Grafana instance (v7.0+ recommended). +- **Prometheus data source** + - Must be added in Grafana and scraping your cluster’s metrics (e.g. via kube-prometheus or another Prometheus setup). +- **Loki data source** + - Must be added in Grafana to include pod logs alongside metrics. +- **Kubernetes metrics exposure** + - Metrics-server or Prometheus exporters installed so that Prometheus can scrape pod-level metrics. + +## Import Dashboard from JSON + +1. In your Grafana UI, click **“Import”**. +2. Under **“Upload JSON file”**, select + `kubernetes/helm/observability/openslice_observability_dashboard.json`. +3. Choose your **Prometheus** data source. +4. Choose your **Loki** data source. +5. Click **“Import”**. +6. In the **“namespace”** variable dropdown, select `openslice`. diff --git a/kubernetes/observability/openslice_observability_dashboard.json b/kubernetes/observability/openslice_observability_dashboard.json new file mode 100644 index 0000000000000000000000000000000000000000..3120d427f1d21cc6d82b185b5dc2722cf5fb5c39 --- /dev/null +++ b/kubernetes/observability/openslice_observability_dashboard.json @@ -0,0 +1,2956 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 30, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 34, + "panels": [], + "title": "Overview", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 1 + }, + "id": 35, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "inverted", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": true, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "100 * sum(rate(container_cpu_usage_seconds_total{namespace=\"$namespace\", container!=\"\", container!=\"POD\"}[5m]))\r\n /\r\nsum(machine_cpu_cores)\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "% CPU Usage", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 1 + }, + "id": 36, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "inverted", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": true, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "100 * sum(container_memory_usage_bytes{namespace=\"$namespace\", container!=\"\", container!=\"POD\"})\r\n /\r\nsum(machine_memory_bytes)\r\n\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "% Memory Usage", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 1 + }, + "id": 37, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": true, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "exemplar": false, + "expr": "count(kube_pod_container_status_waiting_reason{namespace=\"$namespace\", reason=~\"CrashLoopBackOff|ImagePullBackOff|ErrImagePull|Error\"}) or on() vector(0)\r\n", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Pods with Errors", + "type": "stat" + }, + { + "datasource": { + "type": "loki", + "uid": "bezqj2szkivi8d" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 1 + }, + "id": 38, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "inverted", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": true, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "bezqj2szkivi8d" + }, + "direction": "backward", + "editorMode": "code", + "expr": "sum(count_over_time(({namespace=\"$namespace\"} |~ \"(?i)Error\")[$__range])) ", + "queryType": "range", + "refId": "A" + } + ], + "title": "Number of Errors in Logs", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 9 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "avg_over_time(node_cpu_seconds_total{mode=\"iowait\"}[5m])\r\n", + "legendFormat": "{{cpu}}, {{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "CPU Pressure", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 9 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes\r\n", + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Memory Pressure", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 9 + }, + "id": 33, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "100 * (1 - (node_filesystem_avail_bytes{fstype!=\"tmpfs\",fstype!=\"overlay\"} / node_filesystem_size_bytes{fstype!=\"tmpfs\",fstype!=\"overlay\"}))\r\n", + "legendFormat": "{{device}}: {{instance}}", + "range": true, + "refId": "A" + } + ], + "title": "Disk pressure", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 2, + "panels": [], + "title": "Memory Usage", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 15, + "x": 0, + "y": 18 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(\r\n container_memory_working_set_bytes{namespace=\"$namespace\", container!=\"\", container!=\"POD\"}\r\n)\r\n", + "hide": false, + "instant": false, + "legendFormat": "Total memory usage", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum by (pod) (\r\n container_memory_working_set_bytes{namespace=\"$namespace\", container!=\"\", container!=\"POD\"}\r\n)\r\n", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Memory Usage in namespace $namespace", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 9, + "x": 15, + "y": 18 + }, + "id": 3, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "(\r\n sum(container_memory_usage_bytes{namespace=\"$namespace\", container!=\"\", container!=\"POD\"})\r\n /\r\n (sum(kube_node_status_allocatable_memory_bytes) or sum(node_memory_MemTotal_bytes))\r\n) * 100\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "% Memory Usage in namespace $namespace", + "type": "gauge" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 4, + "panels": [], + "title": "CPU Usage", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "cores" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 27 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(\r\n rate(container_cpu_usage_seconds_total{namespace=\"$namespace\", container!=\"\", container!=\"POD\"}[5m])\r\n)\r\n", + "hide": false, + "instant": false, + "legendFormat": "Total CPU usage", + "range": true, + "refId": "B" + }, + { + "editorMode": "code", + "expr": "sum by(pod) (\r\n rate(container_cpu_usage_seconds_total{namespace=\"$namespace\", container!=\"\", container!=\"POD\"}[5m])\r\n)\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "CPU Usage in namespace $namespace", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 27 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "node_load5{instance=~\".*\"}", + "legendFormat": "5m load average on {{instance}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "node_load1{instance=~\".*\"}", + "hide": false, + "instant": false, + "legendFormat": "1m load average on {{instance}}", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "count(node_cpu_seconds_total{instance=~\".*\", mode=\"idle\"})", + "hide": false, + "instant": false, + "legendFormat": "logical cores", + "range": true, + "refId": "C" + } + ], + "title": "Load Average per Instance", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 7, + "panels": [], + "title": "Disk Usage", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "sum by (pod) (\r\n rate(container_fs_reads_total{\r\n namespace=\"$namespace\",\r\n container!=\"\", \r\n container!=\"POD\"\r\n }[5m])\r\n)\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(\r\n rate(container_fs_reads_total{\r\n namespace=\"$namespace\",\r\n container!=\"\", \r\n container!=\"POD\"\r\n }[5m])\r\n)\r\n", + "hide": false, + "instant": false, + "legendFormat": "total disk input operations", + "range": true, + "refId": "B" + } + ], + "title": "Disk Input Operations per pod in namespace $namespace", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "sum by (pod) (\r\n rate(container_fs_writes_total{\r\n namespace=\"$namespace\",\r\n container!=\"\", \r\n container!=\"POD\"\r\n }[5m])\r\n)\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(\r\n rate(container_fs_writes_total{\r\n namespace=\"$namespace\",\r\n container!=\"\", \r\n container!=\"POD\"\r\n }[5m])\r\n)\r\n", + "hide": false, + "instant": false, + "legendFormat": "total disk output operations", + "range": true, + "refId": "B" + } + ], + "title": "Disk Output Operations per pod in namespace $namespace", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 10, + "panels": [], + "title": "Network", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "deckbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 45 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(avg(irate(container_network_receive_bytes_total{namespace=~\"$namespace\"}[$__interval])) by (pod, container))", + "hide": false, + "instant": false, + "legendFormat": "total bytes received", + "range": true, + "refId": "B" + }, + { + "editorMode": "code", + "expr": "avg(irate(container_network_receive_bytes_total{namespace=~\"$namespace\"}[$__interval])) by (pod, container)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Network Received (bytes)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "deckbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 45 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(avg(irate(container_network_transmit_bytes_total{namespace=~\"$namespace\"}[$__interval])) by (pod, container))", + "hide": false, + "instant": false, + "legendFormat": "total bytes transmitted", + "range": true, + "refId": "B" + }, + { + "editorMode": "code", + "expr": "avg(irate(container_network_transmit_bytes_total{namespace=~\"$namespace\"}[$__interval])) by (pod, container)", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Network Transmitted (bytes)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "MBs" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 53 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum by(pod) (\r\n rate(container_network_receive_bytes_total{\r\n namespace=\"$namespace\",\r\n pod!=\"\",\r\n interface!~\"lo\"\r\n }[$__interval])\r\n)\r\n", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Traffic In (Bytes/sec per interface)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "MBs" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 53 + }, + "id": 19, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "sum by(pod) (\r\n rate(container_network_transmit_bytes_total{\r\n namespace=\"$namespace\",\r\n pod!=\"\",\r\n interface!~\"lo\"\r\n }[$__interval])\r\n)\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Traffic Out (Bytes/sec per interface)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 61 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "sum by(pod) (\r\n rate(container_network_receive_errors_total{\r\n namespace=\"$namespace\",\r\n pod!=\"\",\r\n interface!~\"lo\"\r\n }[$__interval])\r\n)\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Errors Rx per pods", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 61 + }, + "id": 21, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "sum by(pod) (\r\n rate(container_network_transmit_errors_total{\r\n namespace=\"$namespace\",\r\n pod!=\"\",\r\n interface!~\"lo\"\r\n }[$__interval])\r\n)\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Errors Tx per pod", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 69 + }, + "id": 13, + "panels": [], + "title": "Namespace Workload Summary", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 9, + "x": 0, + "y": 70 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "exemplar": false, + "expr": "count(\r\n kube_pod_info{namespace=\"$namespace\"}\r\n)\r\n", + "format": "time_series", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Pods Count in namespace $namespace", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 9, + "y": 70 + }, + "id": 15, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "exemplar": false, + "expr": "count(\r\n kube_deployment_created{namespace=\"$namespace\"}\r\n)\r\n", + "format": "time_series", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Deployments Count in namespace $namespace", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 7, + "x": 17, + "y": 70 + }, + "id": 16, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "count(\r\n kube_replicaset_created{namespace=\"$namespace\"}\r\n)\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "ReplicaSet Count in namespace $namespace", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 78 + }, + "id": 17, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "sum(\r\n kube_pod_status_ready{namespace=\"$namespace\", condition=\"true\"}\r\n)\r\n", + "legendFormat": "Ready Pods", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(\r\n kube_deployment_spec_replicas{namespace=\"$namespace\"}\r\n)\r\n", + "hide": false, + "instant": false, + "legendFormat": "Desired pods", + "range": true, + "refId": "B" + } + ], + "title": "Ready Pods vs Desired Pods", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pod" + }, + "properties": [ + { + "id": "custom.width", + "value": 335 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 78 + }, + "id": 22, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 1, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Number of restarts" + } + ] + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (pod) (\r\n kube_pod_container_status_restarts_total{namespace=\"$namespace\"}\r\n)\r\n", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "exemplar": false, + "expr": "kube_pod_status_phase{namespace=\"$namespace\", phase!=\"Unknown\"}==1\r\n", + "format": "table", + "hide": false, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Pod States in Namespace $namespace", + "transformations": [ + { + "id": "joinByField", + "options": { + "byField": "pod", + "mode": "outer" + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time 1": true, + "Time 2": true, + "Value #A": true, + "__name__": true, + "container": true, + "endpoint": true, + "instance": true, + "job": true, + "namespace": true, + "phase": false, + "service": true, + "uid": true + }, + "includeByName": {}, + "indexByName": { + "Time 1": 1, + "Time 2": 2, + "Value #A": 13, + "Value #B": 10, + "__name__": 3, + "container": 4, + "endpoint": 5, + "instance": 6, + "job": 7, + "namespace": 8, + "phase": 9, + "pod": 0, + "service": 11, + "uid": 12 + }, + "renameByName": { + "Time 2": "", + "Value #B": "Number of restarts", + "phase": "State" + } + } + } + ], + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 86 + }, + "id": 23, + "panels": [], + "title": "Resource Saturation", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "applyToRow": false, + "type": "color-background", + "wrapText": false + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 87 + }, + "id": 26, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "exemplar": false, + "expr": "kube_pod_container_status_waiting_reason{\r\n namespace=\"$namespace\",\r\n reason=~\"CrashLoopBackOff|Error|ImagePullBackOff|ErrImagePull|CreateContainerError\"\r\n}\r\nor\r\nkube_pod_status_phase{namespace=\"$namespace\", phase=\"Failed\"} ==1\r\n", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Unhealthy Pods in namespace $namespace", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "__name__": true, + "endpoint": true, + "instance": true, + "job": true, + "namespace": true, + "reason": false, + "service": true, + "uid": true + }, + "includeByName": {}, + "indexByName": {}, + "orderByMode": "manual", + "renameByName": { + "container": "Container Name", + "pod": "Pod Name", + "reason": "Reason" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 87 + }, + "id": 27, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "expr": "sum by (pod) (\r\n rate(container_cpu_cfs_throttled_periods_total{\r\n namespace=\"$namespace\", container!=\"\", container!=\"POD\"\r\n }[5m])\r\n) or on() vector(0)\r\n", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Throttled Containers", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "cores" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 95 + }, + "id": 24, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "exemplar": false, + "expr": "topk(5,\r\n sum by (pod) (\r\n rate(container_cpu_usage_seconds_total{\r\n namespace=\"$namespace\", container!=\"\", container!=\"POD\"\r\n }[$__interval])\r\n )\r\n)\r\n", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Top 5-CPU Hungry Pods in namespace $namespace", + "type": "barchart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 95 + }, + "id": 25, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "editorMode": "code", + "exemplar": false, + "expr": "topk(5,\r\n sum by (pod) (\r\n container_memory_usage_bytes{\r\n namespace=\"$namespace\", container!=\"\", container!=\"POD\"\r\n }\r\n )\r\n)\r\n", + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A" + } + ], + "title": "Top 5-Memory Hungry Pods in namespace $namespace", + "type": "barchart" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 103 + }, + "id": 39, + "panels": [], + "title": "Logs Overview", + "type": "row" + }, + { + "datasource": { + "type": "loki", + "uid": "bezqj2szkivi8d" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "green", + "mode": "fixed" + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 104 + }, + "id": 41, + "options": { + "displayMode": "gradient", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 238, + "namePlacement": "auto", + "orientation": "vertical", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "bezqj2szkivi8d" + }, + "direction": "backward", + "editorMode": "code", + "expr": "topk(5, sum by (pod) (count_over_time(({namespace=\"$namespace\"} |~ \"(?i)error\")[$__range])))", + "legendFormat": "{{pod}}", + "queryType": "range", + "refId": "A" + } + ], + "title": "Top 5 Error Producing Pods", + "type": "bargauge" + }, + { + "datasource": { + "type": "loki", + "uid": "bezqj2szkivi8d" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 104 + }, + "id": 42, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "bezqj2szkivi8d" + }, + "direction": "backward", + "editorMode": "code", + "expr": "sum by (pod) (\r\n count_over_time({namespace=\"$namespace\"} |~ \"(?i)error\" [$__range])\r\n)\r\n", + "legendFormat": "{{pod}}", + "queryType": "range", + "refId": "A" + } + ], + "title": "Error Trends over Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "bezqj2szkivi8d" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 20, + "w": 24, + "x": 0, + "y": 112 + }, + "id": 40, + "options": { + "dedupStrategy": "none", + "enableInfiniteScrolling": true, + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": true + }, + "pluginVersion": "12.1.1", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "bezqj2szkivi8d" + }, + "direction": "backward", + "editorMode": "code", + "expr": "{namespace=\"$namespace\", pod=~\"$pod\"} |~ \"(?i)$log_pattern\"", + "queryType": "range", + "refId": "A" + } + ], + "title": "Namespace Logs", + "type": "logs" + } + ], + "preload": false, + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "monitoring", + "value": "monitoring" + }, + "definition": "label_values(kube_pod_info,namespace)", + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(kube_pod_info,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "", + "value": "" + }, + "description": "Log Pattern to filter logs. Applies only to log section", + "label": "Log Pattern", + "name": "log_pattern", + "options": [ + { + "selected": true, + "text": "", + "value": "" + } + ], + "query": "", + "type": "textbox" + }, + { + "current": { + "text": "All", + "value": "$__all" + }, + "definition": "label_values(kube_pod_info{namespace=\"$namespace\"},pod)", + "description": "Pod filter. This applies only to the Log Section", + "includeAll": true, + "label": "Pod", + "name": "pod", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(kube_pod_info{namespace=\"$namespace\"},pod)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "OpenSlice Observability Dashboard", + "uid": "940f84f4-9844-422d-9308-670b8dfdf46e", + "version": 17 +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 476803810245d5eadcb013bcd877bfcddc6e92e1..f947c052a87551125c82d6297b37aa4ce707e898 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.etsi.osl org.etsi.osl.main - 2025Q2 + 2025Q4 pom org.etsi.osl.main @@ -33,25 +33,27 @@ 1.7.0 - 1.0.2 - 1.0.2 - 1.0.2 - 1.2.0 - 2025Q2 - 1.0.2 - 1.1.1 - 1.1.0 - 1.2.0 - 1.0.2 - 1.2.0 - 1.1.0 - 1.0.2 - 1.0.2 - 1.0.2 - 1.2.0 - 1.2.0 - 1.0.0 - 1.0.0 + 1.0.3 + 1.0.3 + 1.0.3 + 1.3.0 + 2025Q4 + 1.0.3 + 1.1.2 + 1.1.1 + 1.3.0 + 1.0.3 + 1.3.0 + 1.1.1 + 1.0.3 + 1.0.3 + 1.0.3 + 1.3.0 + 1.3.0 + 1.1.0 + 1.1.0 + 1.0.0 +