redhat-developer / intellij-kubernetes

IntelliJ Kubernetes plugin
https://plugins.jetbrains.com/plugin/15921-kubernetes-by-red-hat
Eclipse Public License 2.0
20 stars 20 forks source link

Schema validation does not work with multi-resource documents #630

Open adietish opened 1 year ago

adietish commented 1 year ago

Steps:

  1. EXEC: open the following yaml in an editor
    ---
    apiVersion: v1
    kind: Service
    metadata:
    annotations:
    app.quarkus.io/build-timestamp: 2023-06-30 - 12:24:49 +0000
    labels:
    app.kubernetes.io/name: openshift-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/managed-by: quarkus
    name: openshift-quickstart
    spec:
    ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 8080
    - name: https
      port: 443
      protocol: TCP
      targetPort: 8443
    selector:
    app.kubernetes.io/name: openshift-quickstart
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    annotations:
    app.quarkus.io/build-timestamp: 2023-06-30 - 12:24:49 +0000
    labels:
    app.kubernetes.io/managed-by: quarkus
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
    app.kubernetes.io/name: openshift-quickstart
    name: openshift-quickstart
    spec:
    replicas: 1
    selector:
    matchLabels:
      app.kubernetes.io/version: 1.0.0-SNAPSHOT
      app.kubernetes.io/name: openshift-quickstart
    template:
    metadata:
      annotations:
        app.quarkus.io/build-timestamp: 2023-06-30 - 12:24:49 +0000
      labels:
        app.kubernetes.io/managed-by: quarkus
        app.kubernetes.io/version: 1.0.0-SNAPSHOT
        app.kubernetes.io/name: openshift-quickstart
    spec:
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: adietish/openshift-quickstart:1.0.0-SNAPSHOT
          imagePullPolicy: Always
          name: openshift-quickstart
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP
            - containerPort: 8443
              name: https
              protocol: TCP
  2. EXEC: put your cursor to the 2nd resource, a Deployment
  3. EXEC: inspect the schema that is applied. It is shown in the right corner of the status bar:

Result: The schema that is applied still is Service (first resource in the document)

image
adietish commented 10 months ago

It very much looks like the current platform schema validation framework only supports using a single schema file per editor. It seems unable to use multiple schema files per json/yaml file that is edited (multi-resource files contains multiple individual resources separated by --- and each resource should be validated against it's own schema). If this is confirmed we'd have to get away from using or extending the platform implementation.

adietish commented 10 months ago

in vscode this was requested and they found a workaround indicating the schemas: https://github.com/redhat-developer/vscode-yaml/issues/702#issuecomment-1048518781

adietish commented 10 months ago

I tried to provide KubernetesSchemaProviders which would return true if one of the resources in the file match the typeinfo in the schema provider:

    override fun isAvailable(file: VirtualFile): Boolean {
        return ApplicationManager.getApplication().runReadAction(
            Computable {
/*
                val psiFile = PsiManager.getInstance(project!!).findFile(file)
                if (psiFile == null) {
                    false
                } else {
                    val fileInfo = KubernetesTypeInfo.extractMeta(psiFile)
                    info == fileInfo
                }
*/
                val fileContent = String(file.contentsToByteArray(true))
                val resources = EditorResourceSerialization.deserialize(fileContent, file.fileType, null)
                resources.any { resource ->
                    info.kind == resource.kind
                            && info.apiGroup == resource.apiVersion
                }
        })
    }

But this results in no schema being considered at all.

adietish commented 10 months ago

I dug into the json plugin/platform and found out that the validation is done on behalf of JsonSchemaComplianceChecker. Interestingly JsonSchemaComplianceChecker#annotate() is called 3 times for the 3 resources. The root schema is the deployment schema though. Maybe if we can provide a composite schema which holds the 3 schema would help work around it.

JsonSchemaComplianceChecker is created by JsonSchemaComplianceInspection which is declared as local inspection in the json plugin:

    <localInspection language="JSON" shortName="JsonSchemaCompliance"
                     bundle="messages.JsonBundle" key="json.schema.inspection.compliance.name" groupKey="json.inspection.group"
                     enabledByDefault="true" level="WARNING"
                     implementationClass="com.jetbrains.jsonSchema.impl.inspections.JsonSchemaComplianceInspection"/>
adietish commented 10 months ago

I talked to Yann Cébron on Jetbrains Slack #intellij-platform and he told me that he'd investigate the possibilities to use several schemas to validate a single json/yaml file.