grafana/apps/example/README.md

3.7 KiB

Example App

This App is an example of general app capabilities when developing on the grafana app platform.

Enabling the App

By default, the example app is disabled. To enable this App, add the following to your conf/custom.ini:

[grafana-apiserver]
runtime_config = example.grafana.app/v0alpha1=true,example.grafana.app/v1alpha1=true

Manifest

The source of the app's schemas and list of capabilities is the manifest, which is generated from kinds/manifest.cue. The Example kind is defined for v0alpha1 here and v1alpha1 (default) here. The root definition of the Example kind that both versions share is defined here.

The CUE is used to generate code (and the AppManifest) when make generate is run.

Code

All of the app's code is located in pkg/app. The New() function in pkg/app/app.go is the entry point of the app, and everything should be discoverable from there.

The code to register the app with the grafana API server (including inserting the app-specific config ExampleConfig) is located in /pkg/registry/apps/example/register.go.

Any app must also have its installer listed in WireSet and added to installers in ProvideAppInstallers. When building a new app, make to to regerate wire (make build in the root of the repo does this).

Generated Code

The pkg/apis package, and all its subdirectories, contain code generated by make generate. This code should not be edited, but it can be useful to look at when working through the flow of the app.

Sample Swagger Payloads

Navigate to localhost:3000/swagger?api=example.grafana.app-v1alpha1 to view the swagger for the app's v1alpha1 version (this version has the most capabilities/endpoints). You can use the Execute button to make requests via the swagger UI.

Create a new Example resource with via swagger with:

{
  "apiVersion": "example.grafana.app/v1alpha1",
  "kind": "Example",
  "metadata": {
    "name": "test",
    "namespace": "default"
  },
  "spec": {
    "firstField": "test",
    "secondField": 0,
    "list": {
      "info": "foo",
      "next": {
        "info": "bar"
      }
    }
  }
}

Create an invalid object which will be rejected by validation:

{
  "apiVersion": "example.grafana.app/v1alpha1",
  "kind": "Example",
  "metadata": {
    "name": "invalid",
    "namespace": "default"
  },
  "spec": {
    "firstField": "test",
    "secondField": 0,
    "list": {
      "info": "foo",
      "next": {
        "info": "bar"
      }
    }
  }
}

Update custom subresource:

{
  "apiVersion": "example.grafana.app/v1alpha1",
  "kind": "Example",
  "metadata": {
    "namespace": "default",
    "name": "test",
    "resourceVersion": "<REPLACEME>"
  },
  "custom": {
    "myField": "foo",
    "otherField": "bar"
  }
}

(metadata.resourceVersion is required for an update, use the value you get from a GET request)

cURL

You can also interact with the grafana API server via a kubeconfig set up for it, or via curl using the -u <username>:<password> flag. Currently, cluster-scoped custom routes are erased from the swagger as part of grafana's APIServer code, but can still be called via curl, like so:

curl -u admin:admin http://localhost:3000/apis/example.grafana.app/v1alpha1/other
% curl -u admin:admin http://localhost:3000/apis/example.grafana.app/v1alpha1/other
{"message":"This is a cluster route"}