redhat-developer / yaml-language-server

Language Server for YAML Files
MIT License
1.04k stars 256 forks source link

Feature Request: support for Kubernetes CRDs #132

Open lionelvillard opened 5 years ago

lionelvillard commented 5 years ago

I tried to use yaml.schemas to associate kubernetes CRD schemas but this is not working. I added this entry to vscode user settings:

"yaml.schemas": {
        "file:///path/to/application-swagger-latest.json": "/**"
    }

I also tried:

"yaml.schemas": {
        ./path/to/application-swagger-latest.json": "/**"
    }

with no success.

JPinkney commented 5 years ago

I'm not sure where "./path/to/application-swagger-latest.json" to points too but the path has to be relative to the root of the folder you have opened

For example, if the project hierarchy is:

Myfolder (this being the root)
  - my_schema.json
  - my_file.yaml

you should just need to do

"yaml.schemas": {
        "./my_schema.json": "/**"
}

and it should pick it up in my_file.yaml. If it doesn't not let me know and I can try and look into it further!

lionelvillard commented 5 years ago

I tried multiple configurations, no success so far. My environment is vscode with only one folder open. After changing the configuration I reloaded the window.

First configuration:

schemas/
  application-swagger-latest.json
  app.yaml

user settings:

"yaml.schemas": {
        "./schemas/application-swagger-latest.json": "./schemas/app.yaml"
    }

I get this error: Unable to load schema from 'kubernetes://schema/app.k8s.io@application': No content.

Second configuration:

./
  application-swagger-latest.json
  app.yaml

user settings:

"yaml.schemas": {
        "./application-swagger-latest.json": "./app.yaml"
    }

Error: I get this error: Unable to load schema from 'kubernetes://schema/app.k8s.io@application': No content.

Maybe schema extension does not work for Kubernetes YAMLs?

JPinkney commented 5 years ago

So if you're getting that error that means that its at least attempting to associate the schema to the file. Is there anyway you can post the schema and the contents of the text file. Presumably kubernetes://schema/app.k8s.io@application error is because it thinks its an address where it can grab content from but I don't know enough about kubernetes to know whether that is an actually somewhere that it can grab content from or if the problem is that the language server is attempting to resolve it when it shouldn't.

lionelvillard commented 5 years ago

the schema is this one:

{
  "oneOf": [
    {
      "$ref": "#/definitions/com.github.kubernetes-sigs.application.pkg.apis.app.v1beta1.Application"
    }
  ],
  "definitions": {
    "com.github.kubernetes-sigs.application.pkg.apis.app.v1beta1.Application": {
      "description": "Application is the Schema for the applications API",
      "type": "object",
      "properties": {
        "apiVersion": {
          "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources",
          "type": "string"
        },
        "kind": {
          "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
          "type": "string"
        },
        "metadata": {
          "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"
        },
        "spec": {
          "$ref": "#/definitions/com.github.kubernetes-sigs.application.pkg.apis.app.v1beta1.ApplicationSpec"
        },
        "status": {
          "$ref": "#/definitions/com.github.kubernetes-sigs.application.pkg.apis.app.v1beta1.ApplicationStatus"
        }
      },
      "x-kubernetes-group-version-kind": [
        {
          "group": "app.k8s.io",
          "version": "v1beta1",
          "kind": "Application"
        }
      ]
    },
...
julianKatz commented 2 years ago

I'd love to see a way to easily exempt certain files from validation. That would be enough for me day-to-day. For example, any file named my_custom_resource.yaml would be exempt from validation.

Is there a way to do that with the current glob support?

Cerebus commented 1 year ago

If anyone is still following this, the underlying problem seems to be that the OpenAPIv3 doesn't validate against JSON schema, mainly b/c of circular references. The published K8s Open schemas are converted using openapi2jsonschema.

So--

Caveats--

ETA: I am getting back an interesting error:

[server-notification] Wed Jan 25 10:44:05 2023:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
          (:uri "file:///Users/some/path/examples/meteor-load/base/cm.yaml" :diagnostics
                [(:range
                  (:start
                   (:line 1 :character 0)
                   :end
                   (:line 1 :character 1))
                  :message "Matches multiple schemas when only one must validate." :severity 1 :code 0 :source "yaml-schema: file:///Users/some/path/prototype/scratch/prototype-standalone/all.json" :data
                  (:schemaUri
                   ["file:///Users/some/path/prototype/scratch/prototype-standalone/all.json"]))]))

This doesn't seem to be affecting anything, b/c standard K8s resources are validating/completing, but CRDs do not. So...working as designed, maybe?

Cerebus commented 1 year ago

Ok, this is progress of a sort:

[client-request] (id:74) Wed Jan 25 14:02:36 2023:
(:jsonrpc "2.0" :id 74 :method "textDocument/completion" :params
          (:textDocument
           (:uri "file:///Users/some/path/prototype/examples/meteor-load/base/flink.yaml")
           :position
           (:line 6 :character 5)
           :context
           (:triggerKind 1)))
[server-reply] (id:74) Wed Jan 25 14:02:36 2023:
(:jsonrpc "2.0" :id 74 :result
          (:items
           [(:kind 10 :label "flinkConfiguration" :insertText "flinkConfiguration:\n  " :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "flinkConfiguration:\n  "))
            (:kind 10 :label "flinkVersion" :insertText "flinkVersion: " :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "flinkVersion: "))
            (:kind 10 :label "image" :insertText "image: " :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "image: "))
            (:kind 10 :label "imagePullPolicy" :insertText "imagePullPolicy: " :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "imagePullPolicy: "))
            (:kind 10 :label "ingress" :insertText "ingress:\n  " :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "ingress:\n  "))
            (:kind 10 :label "job" :insertText "job:\n  " :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "job:\n  "))
            (:kind 10 :label "jobManager" :insertText "jobManager:\n  " :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "jobManager:\n  "))
            (:kind 10 :label "logConfiguration" :insertText "logConfiguration:\n  " :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "logConfiguration:\n  "))
            (:kind 10 :label "mode" :insertText "mode: " :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "mode: "))
            (:kind 10 :label "podTemplate" :insertText "podTemplate:\n  " :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "podTemplate:\n  "))
            (:kind 10 :label "restartNonce" :insertText "restartNonce: ${1:0}" :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "restartNonce: ${1:0}"))
            (:kind 10 :label "serviceAccount" :insertText "serviceAccount: " :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "serviceAccount: "))
            (:kind 10 :label "taskManager" :insertText "taskManager:\n  " :insertTextFormat 2 :documentation "" :textEdit
                   (:range
                    (:start
                     (:line 6 :character 2)
                     :end
                     (:line 6 :character 5))
                    :newText "taskManager:\n  "))]
           :isIncomplete :json-false))

So clearly this is an issue with the CRDs. Maybe it's down to the version of kubebuilder or whatever, or specific options therein.

Cerebus commented 1 year ago

There's some kind of parse error in here, b/c if I explicitly ask for completion at point, where point is a blank line immediately after the kind, I get a completion offering the fields name, uid, fieldPath, namespace, and resourceVersion. None of which appear in this specific kind. 🤔

image

From the description strings, name and uid seem to be coming from BoundObjectReference, while fieldPath, namespace, and resourceVersion are coming from ObjectReference.

Cerebus commented 1 year ago

And this is really weird: image

samos667 commented 4 months ago

My behavior is really funny too. I test with flux CRD "Kustomization". This is my schema config:

"https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/kustomization-kustomize-v1.json" = "*.k8s.ccrd.flux.k.yaml",
"https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.29.4/all.json"="*.k8s.*.yaml",

When I edit a file name test.k8s.crrd.flux.k.yaml, in spec when I ask completion with this "r". image

I got "replicas" as possibility (+ all other possibilities in a spec:) and when I select it and go in normal mode, I got this message: image

That tell me I'm wrong and it's totally true.

I have found only this way to manage schema detection work. If someone have a better solution to get custom CRD work I take it !