# Dépôt chart helm pour l'ajout d'un catalogue de service visible sur l'interface onyxia uniquement par les utilisateurs étant dans un groupe spécifique + ajout du service wordpress. Nous utilisons le chart helm de https://artifacthub.io/packages/helm/bitnami/wordpress Un groupe de projet "datalab-onyxia-admin" a été créer sur l'AD dans le dossier datalab/onyxia Concernant le chart helm wordpress, pour la personnalisation de l'UI et des valeurs que l'utilisateur pourra paramétrer lors ce qu'il lancera le service "wordpress" depuis le catalogue. Il va falloir modifier des valeurs dans le fichier "values.schema.json" du chart helm wordpress. Ceci est expliqué avec des exemples dans la partie "Onyxia Helm format extension" disponible sur https://github.com/InseeFrLab/onyxia-api/tree/main ## ON GOING **Helm chart repo**: https://code.groupe-genes.fr/aguyot-ensae/-/packages **Code des helm chart repo** https://code.groupe-genes.fr/aguyot-ensae/helm-chart-genes/src/branch/main/charts **Helm chart wordpress+valuesjson de VScode** Plusieurs tentatives de mixer le values.schema. json pas du chart wordpress et celui du values.json du VScode de l’insee, pas d’erreur significatif sur l’api, le service depuis le catalog ne se lance pas (tourne en boucle + n’apparait pas dans « Mes services » + aucun pod de lancé). **Helm chart du wordpress sans values.schema.json** Erreur Pkg sur l’api : ``` 2024-04-16T08:43:49.610Z ERROR 7 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [/api] threw exception [Request processing failed: java.lang.NullPointerException: Cannot invoke "fr.insee.onyxia.model.catalog.Config.Config.getProperties()" because the return value of "fr.insee.onyxia.model.catalog.Pkg.getConfig()" is null] with root cause java.lang.NullPointerException: Cannot invoke "fr.insee.onyxia.model.catalog.Config.Config.getProperties()" because the return value of "fr.insee.onyxia.model.catalog.Pkg.getConfig()" is null at fr.insee.onyxia.api.controller.pub.CatalogController.addCustomOnyxiaProperties(CatalogController.java:148) ~[classes/:v2.5.0] at fr.insee.onyxia.api.controller.pub.CatalogController.getChartByVersion(CatalogController.java:119) ~[classes/:v2.5.0] at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na] ``` **Helm chart du wordpress avec uniquement les values.schema.json du wordpress** ``` Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `fr.insee.onyxia.model.catalog.Config.Property$Hidden` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('mariadb/enabled') at [Source: (org.apache.commons.compress.archivers.tar.TarArchiveInputStream); line: 86, column: 21] (through reference chain: fr.insee.onyxia.model.catalog.Config.Config["properties"]->fr.insee.onyxia.model.catalog.Config.Category["externalDatabase"]->fr.insee.onyxia.model.catalog.Config.Property["properties"]->java.util.LinkedHashMap["host"]->fr.insee.onyxia.model.catalog.Config.Property["hidden"]) at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63) ~[jackson-databind-2.15.4.jar:2.15.4] ``` ### Problème 1 Erreur dû au fichier values.schema.json du chart wordpress L'erreur affiché est du côté de l'api dans le catalogcontroller: https://github.com/InseeFrLab/onyxia-api/blob/5bd597127bbeeb22d155494d9632dfcaf1c28d1d/onyxia-api/src/main/java/fr/insee/onyxia/api/controller/pub/CatalogController.java#L147 ``` 2024-04-15T13:44:00.432Z INFO 7 --- [Pool-worker-254] f.i.o.api.dao.universe.CatalogLoader : Refreshing package wordpress-copie-original version 20.1.2 in catalog Genes 2024-04-15T13:44:00.432Z INFO 7 --- [Pool-worker-268] f.i.o.api.dao.universe.CatalogLoader : Refreshing package kikik version 2.1 in catalog Genes 2024-04-15T13:44:00.461Z INFO 7 --- [Pool-worker-254] f.i.o.api.dao.universe.CatalogLoader : Exception occurred fr.insee.onyxia.api.dao.universe.CatalogLoaderException: Exception occurred during loading resource: URL [https://code.groupe-genes.fr/api/packages/aguyot-ensae/helm/wordpress-copie-original-20.1.2.tgz] at fr.insee.onyxia.api.dao.universe.CatalogLoader.refreshPackage(CatalogLoader.java:171) ~[classes/:v2.5.0] at fr.insee.onyxia.api.dao.universe.CatalogLoader.lambda$refreshChartsList$3(CatalogLoader.java:133) ~[classes/:v2.5.0] at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source) ~[na:na] at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(Unknown Source) ~[na:na] at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source) ~[na:na] at java.base/java.util.stream.ForEachOps$ForEachTask.compute(Unknown Source) ~[na:na] at java.base/java.util.concurrent.CountedCompleter.exec(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ForkJoinTask.doExec(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ForkJoinTask.invoke(Unknown Source) ~[na:na] at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(Unknown Source) ~[na:na] at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(Unknown Source) ~[na:na] at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source) ~[na:na] at java.base/java.util.stream.ReferencePipeline.forEach(Unknown Source) ~[na:na] at java.base/java.util.stream.ReferencePipeline$Head.forEach(Unknown Source) ~[na:na] at fr.insee.onyxia.api.dao.universe.CatalogLoader.refreshChartsList(CatalogLoader.java:130) ~[classes/:v2.5.0] at fr.insee.onyxia.api.dao.universe.CatalogLoader.lambda$updateHelmRepository$2(CatalogLoader.java:83) ~[classes/:v2.5.0] at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source) ~[na:na] at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Unknown Source) ~[na:na] at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source) ~[na:na] at java.base/java.util.stream.ForEachOps$ForEachTask.compute(Unknown Source) ~[na:na] at java.base/java.util.concurrent.CountedCompleter.exec(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ForkJoinTask.doExec(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ForkJoinPool.scan(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ForkJoinPool.runWorker(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ForkJoinWorkerThread.run(Unknown Source) ~[na:na] Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `fr.insee.onyxia.model.catalog.Config.Property$Hidden` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('mariadb/enabled') at [Source: (org.apache.commons.compress.archivers.tar.TarArchiveInputStream); line: 86, column: 21] (through reference chain: fr.insee.onyxia.model.catalog.Config.Config["properties"]->fr.insee.onyxia.model.catalog.Config.Category["externalDatabase"]->fr.insee.onyxia.model.catalog.Config.Property["properties"]->java.util.LinkedHashMap["host"]->fr.insee.onyxia.model.catalog.Config.Property["hidden"]) ``` Contenu du fichier values.schema.json du helm chart wordpress (j'ai repris le "values.schema.json" du chart original wordpress que j'ai modifié puis j'ai rajouté à la suite le contenue du fichier "values.schema.json" du fichier helm VScode de l'insee et l'ai également modifié. Vu qu'on ne peu pas ajouter de commentaire, j'ai laisser un gros espace vide entre les deux parties dans le values.schema.json): ``` { "$schema": "http://json-schema.org/schema#", "type": "object", "properties": { "wordpressUsername": { "type": "string", "title": "Username", "form": true }, "wordpressPassword": { "type": "string", "title": "Password", "form": true, "description": "Defaults to a random 10-character alphanumeric string if not set" }, "wordpressEmail": { "type": "string", "title": "Admin email", "form": true }, "wordpressBlogName": { "type": "string", "title": "Blog Name", "form": true }, "persistence": { "type": "object", "properties": { "size": { "type": "string", "title": "Persistent Volume Size", "form": true, "render": "slider", "sliderMin": 1, "sliderMax": 100, "sliderUnit": "Gi" } } }, "mariadb": { "type": "object", "title": "MariaDB Details", "form": true, "properties": { "enabled": { "type": "boolean", "title": "Use a new MariaDB database hosted in the cluster", "form": true, "description": "Whether to deploy a mariadb server to satisfy the applications database requirements. To use an external database switch this off and configure the external database details" }, "primary": { "type": "object", "properties": { "persistence": { "type": "object", "properties": { "size": { "type": "string", "title": "Volume Size", "form": true, "hidden": { "value": false, "path": "mariadb/primary/persistence/enabled" }, "render": "slider", "sliderMin": 1, "sliderMax": 100, "sliderUnit": "Gi" } } } } } } }, "externalDatabase": { "type": "object", "title": "External Database Details", "description": "If MariaDB is disabled. Use this section to specify the external database details", "form": true, "properties": { "host": { "type": "string", "form": true, "title": "Database Host", "hidden": "mariadb/enabled" }, "user": { "type": "string", "form": true, "title": "Database Username", "hidden": "mariadb/enabled" }, "password": { "type": "string", "form": true, "title": "Database Password", "hidden": "mariadb/enabled" }, "database": { "type": "string", "form": true, "title": "Database Name", "hidden": "mariadb/enabled" }, "port": { "type": "integer", "form": true, "title": "Database Port", "hidden": "mariadb/enabled" } } }, "ingress": { "type": "object", "form": true, "title": "Ingress Configuration", "properties": { "enabled": { "type": "boolean", "form": true, "title": "Use a custom hostname", "description": "Enable the ingress resource that allows you to access the WordPress installation." }, "hostname": { "type": "string", "form": true, "title": "Hostname", "hidden": { "value": false, "path": "ingress/enabled" } }, "tls": { "type": "boolean", "form": true, "title": "Create a TLS secret", "hidden": { "value": false, "path": "ingress/enabled" } } } }, "service": { "type": "object", "form": true, "title": "Service Configuration", "properties": { "type": { "type": "string", "form": true, "title": "Service Type", "description": "Allowed values: \"ClusterIP\", \"NodePort\" and \"LoadBalancer\"" } } }, "resources": { "type": "object", "title": "Required Resources", "description": "Your service will have at least the requested resources and never more than its limits. No limit for a resource and you can consume everything left on the host machine.", "properties": { "requests": { "description": "Guaranteed resources", "type": "object", "properties": { "memory": { "description": "The amount of memory guaranteed", "title": "memory", "type": "string", "default": "2Gi", "render": "slider", "sliderMin": 1, "sliderMax": 20, "sliderStep": 1, "sliderUnit": "Gi", "sliderExtremity": "down", "sliderExtremitySemantic": "guaranteed", "sliderRangeId": "memory", "x-onyxia": { "overwriteDefaultWith": "region.resources.memoryRequest", "useRegionSliderConfig": "memory" } }, "cpu": { "description": "The amount of cpu guaranteed", "title": "CPU", "type": "string", "default": "100m", "render": "slider", "sliderMin": 50, "sliderMax": 40000, "sliderStep": 50, "sliderUnit": "m", "sliderExtremity": "down", "sliderExtremitySemantic": "guaranteed", "sliderRangeId": "cpu", "x-onyxia": { "overwriteDefaultWith": "region.resources.cpuRequest", "useRegionSliderConfig": "cpu" } } } }, "limits": { "description": "max resources", "type": "object", "properties": { "cpu": { "description": "The maximum amount of cpu", "title": "CPU", "type": "string", "default": "30000m", "render": "slider", "sliderMin": 50, "sliderMax": 40000, "sliderStep": 50, "sliderUnit": "m", "sliderExtremity": "up", "sliderExtremitySemantic": "Maximum", "sliderRangeId": "cpu", "x-onyxia": { "overwriteDefaultWith": "region.resources.cpuLimit", "useRegionSliderConfig": "cpu" } }, "memory": { "description": "The maximum amount of memory", "title": "Memory", "type": "string", "default": "50Gi", "render": "slider", "sliderMin": 1, "sliderMax": 200, "sliderStep": 1, "sliderUnit": "Gi", "sliderExtremity": "up", "sliderExtremitySemantic": "Maximum", "sliderRangeId": "memory", "x-onyxia": { "overwriteDefaultWith": "region.resources.memoryLimit", "useRegionSliderConfig": "memory" } } } } } }, "volumePermissions": { "type": "object", "properties": { "enabled": { "type": "boolean", "form": true, "title": "Enable Init Containers", "description": "Use an init container to set required folder permissions on the data volume before mounting it in the final destination" } } }, "metrics": { "type": "object", "properties": { "enabled": { "type": "boolean", "title": "Enable Metrics", "description": "Prometheus Exporter / Metrics", "form": true } } }, "security": { "description": "security specific configuration", "type": "object", "properties": { "password": { "type": "string", "description": "Password", "default": "changeme", "render": "password", "x-onyxia": { "overwriteDefaultWith": "{{project.password}}" } }, "allowlist": { "type": "object", "description": "IP protection", "properties": { "enabled": { "type": "boolean", "title": "Enable IP protection", "description": "Only the configured set of IPs will be able to reach the service", "default": true, "x-onyxia": { "overwriteDefaultWith": "region.defaultIpProtection" } }, "ip": { "type": "string", "description": "the white list of IP is whitespace", "title": "Whitelist of IP", "x-onyxia": { "overwriteDefaultWith": "{{user.ip}}" } } } }, "networkPolicy": { "type": "object", "description": "Define access policy to the service", "properties": { "enabled": { "type": "boolean", "title": "Enable network policy", "description": "Only pod from the same namespace will be allowed", "default": true, "x-onyxia": { "overwriteDefaultWith": "region.defaultNetworkPolicy" } }, "from": { "type": "array", "description": "Array of source allowed to have network access to your service", "default": [], "x-onyxia": { "hidden": true, "overwriteDefaultWith": "region.from" } } } } } }, "kubernetes": { "description": "configuration of your kubernetes access", "type": "object", "properties": { "enabled": { "type": "boolean", "description": "allow your service to access your namespace ressources", "default": true }, "role": { "type": "string", "description": "bind your service account to this kubernetes default role", "default": "view", "hidden": { "value": false, "path": "kubernetes/enabled" }, "enum": [ "view", "edit", "admin" ] } } }, "git": { "description": "Git user configuration", "type": "object", "properties": { "enabled": { "type": "boolean", "description": "Add git config inside your environment", "default": true }, "name": { "type": "string", "description": "user name for git", "default": "", "x-onyxia": { "overwriteDefaultWith": "{{git.name}}" }, "hidden": { "value": false, "path": "git/enabled" } }, "email": { "type": "string", "description": "user email for git", "default": "", "x-onyxia": { "overwriteDefaultWith": "{{git.email}}" }, "hidden": { "value": false, "path": "git/enabled" } }, "cache": { "type": "string", "description": "duration in seconds of the credentials cache duration", "default": "", "x-onyxia": { "overwriteDefaultWith": "{{git.credentials_cache_duration}}" }, "hidden": { "value": false, "path": "git/enabled" } }, "token": { "type": "string", "description": "personal access token", "default": "", "render": "password", "x-onyxia": { "overwriteDefaultWith": "{{git.token}}" }, "hidden": { "value": false, "path": "git/enabled" } }, "repository": { "type": "string", "description": "projet", "default": "", "x-onyxia": { "overwriteDefaultWith": "{{git.project}}" }, "hidden": { "value": false, "path": "git/enabled" } }, "branch": { "type": "string", "description": "Branch automatically checked out", "default": "", "hidden": { "value": "", "path": "git/repository" } } } }, "vault": { "description": "Configuration of vault client", "type": "object", "properties": { "enabled": { "type": "boolean", "description": "Add vault temporary identity inside your environment", "default": true }, "token": { "description": "token vault", "type": "string", "render": "password", "x-onyxia": { "overwriteDefaultWith": "{{vault.VAULT_TOKEN}}" }, "hidden": { "value": false, "path": "vault/enabled" } }, "url": { "description": "url of vault server", "type": "string", "x-onyxia": { "overwriteDefaultWith": "{{vault.VAULT_ADDR}}" }, "hidden": { "value": false, "path": "vault/enabled" } }, "mount": { "description": "mount of the v2 secret engine", "type": "string", "x-onyxia": { "overwriteDefaultWith": "{{vault.VAULT_MOUNT}}" }, "hidden": { "value": false, "path": "vault/enabled" } }, "directory": { "description": "top level directory", "type": "string", "x-onyxia": { "overwriteDefaultWith": "{{vault.VAULT_TOP_DIR}}" }, "hidden": { "value": false, "path": "vault/enabled" } }, "secret": { "description": "the path of the secret to convert into a list of environment variables", "type": "string", "default": "", "hidden": { "value": false, "path": "vault/enabled" } } } }, "s3": { "description": "Configuration of temporary identity", "type": "object", "properties": { "enabled": { "type": "boolean", "description": "Add S3 temporary identity inside your environment", "default": true }, "accessKeyId": { "description": "AWS Access Key", "type": "string", "x-onyxia": { "overwriteDefaultWith": "s3.AWS_ACCESS_KEY_ID" }, "hidden": { "value": false, "path": "s3/enabled" } }, "endpoint": { "description": "AWS S3 Endpoint", "type": "string", "x-onyxia": { "overwriteDefaultWith": "{{s3.AWS_S3_ENDPOINT}}" }, "hidden": { "value": false, "path": "s3/enabled" } }, "defaultRegion": { "description": "AWS S3 default region", "type": "string", "x-onyxia": { "overwriteDefaultWith": "{{s3.AWS_DEFAULT_REGION}}" }, "hidden": { "value": false, "path": "s3/enabled" } }, "secretAccessKey": { "description": "AWS S3 secret access key", "type": "string", "render": "password", "x-onyxia": { "overwriteDefaultWith": "{{s3.AWS_SECRET_ACCESS_KEY}}" }, "hidden": { "value": false, "path": "s3/enabled" } }, "sessionToken": { "description": "AWS S3 session Token", "type": "string", "render": "password", "x-onyxia": { "overwriteDefaultWith": "{{s3.AWS_SESSION_TOKEN}}" }, "hidden": { "value": false, "path": "s3/enabled" } } } }, "ingress": { "type": "object", "form": true, "title": "Ingress Details", "properties": { "enabled": { "description": "Enable Ingress", "type": "boolean", "default": true, "x-onyxia": { "hidden": true, "overwriteDefaultWith": "k8s.ingress" } }, "hostname": { "type": "string", "form": true, "title": "Hostname", "x-onyxia": { "hidden": true, "overwriteDefaultWith": "{{project.id}}-{{k8s.randomSubdomain}}-0.{{k8s.domain}}" } }, "userHostname": { "type": "string", "form": true, "title": "Hostname", "x-onyxia": { "hidden": true, "overwriteDefaultWith": "{{project.id}}-{{k8s.randomSubdomain}}-user.{{k8s.domain}}" } }, "ingressClassName": { "type": "string", "form": true, "title": "ingressClassName", "default": "", "x-onyxia": { "hidden": true, "overwriteDefaultWith": "{{k8s.ingressClassName}}" } }, "useCertManager": { "type": "boolean", "description": "Whether CertManager should be used to generate a certificate", "default": false, "x-onyxia": { "hidden": true, "overwriteDefaultWith": "k8s.useCertManager" } }, "certManagerClusterIssuer":{ "type": "string", "description": "certManager cluster issuer", "title": "CertManager Cluster Issuer", "default": "", "x-onyxia": { "hidden": true, "overwriteDefaultWith": "k8s.certManagerClusterIssuer" } } } }, "route": { "type": "object", "form": true, "title": "Route details", "properties": { "enabled": { "description": "Enable route", "type": "boolean", "default": false, "x-onyxia": { "hidden": true, "overwriteDefaultWith": "k8s.route" } }, "hostname": { "type": "string", "form": true, "title": "Hostname", "x-onyxia": { "hidden": true, "overwriteDefaultWith": "{{project.id}}-{{k8s.randomSubdomain}}-0.{{k8s.domain}}" } }, "userHostname": { "type": "string", "form": true, "title": "Hostname", "x-onyxia": { "hidden": true, "overwriteDefaultWith": "{{project.id}}-{{k8s.randomSubdomain}}-user.{{k8s.domain}}" } } } }, "networking": { "type": "object", "form": true, "title": "Networking detail", "properties": { "user": { "type": "object", "description": "user defined port", "properties": { "enabled": { "type": "boolean", "title": "Enable a custom service port", "description": "Enable a custom service port", "default": false }, "port": { "type": "integer", "description": "port of the custom service", "title": "Custom service port", "hidden": { "value": false, "path": "networking/user/enabled" }, "default": 5000 } } } } }, "init": { "description": "Init parameters", "type": "object", "properties": { "regionInit": { "type": "string", "description": "region initialization script", "default": "", "x-onyxia": { "hidden": true, "overwriteDefaultWith": "{{k8s.initScriptUrl}}" } }, "regionInitCheckSum": { "type": "string", "description": "region initialization script", "default": "", "x-onyxia": { "hidden": true, "overwriteDefaultWith": "{{k8s.initScriptCheckSum}}" } }, "personalInit": { "type": "string", "description": "user initialization script", "default": "" }, "personalInitArgs": { "type": "string", "description": "args for user initialization script", "default": "" } } }, "repository": { "description": "python repositories for pip and conda", "type": "object", "properties": { "pipRepository": { "type": "string", "description": "python repository for pip", "default": "", "x-onyxia": { "hidden": true, "overwriteDefaultWith": "{{packageRepositoryInjection.pypiProxyUrl}}" } }, "condaRepository": { "type": "string", "description": "python repository for pip", "default": "", "x-onyxia": { "hidden": true, "overwriteDefaultWith": "{{packageRepositoryInjection.condaProxyUrl}}" } } } }, "startupProbe": { "type": "object", "description": "Start up probe", "default": {}, "x-onyxia": { "hidden": true, "overwriteDefaultWith": "region.startupProbe" } }, "tolerations": { "type": "array", "description": "Array of tolerations", "default": [], "x-onyxia": { "hidden": true, "overwriteDefaultWith": "region.tolerations" } }, "nodeSelector": { "type": "object", "description": "NodeSelector", "default": {}, "x-onyxia": { "hidden": true, "overwriteDefaultWith": "region.nodeSelector" } }, "userPreferences": { "description": "User Preferences", "type": "object", "properties": { "darkMode": { "type": "boolean", "description": "dark mode is or is not enabled", "default": false, "x-onyxia": { "hidden": true, "overwriteDefaultWith": "user.darkMode" } }, "language": { "type": "string", "description": "Preferred language", "default": "en", "x-onyxia": { "hidden": true, "overwriteDefaultWith": "user.lang" } } } }, "global": { "description": "Suspend", "type": "object", "properties": { "suspend": { "type": "boolean", "description": "Suspend this service", "default": false, "x-onyxia": { "hidden": true } } } } } } ```