Skip to content

Latest commit

 

History

History
150 lines (128 loc) · 7.05 KB

File metadata and controls

150 lines (128 loc) · 7.05 KB

Generating Kind Code

Now that we have our kind and schema defined, we want to generate code from them that we can use. In the future, we'll want to re-generate this code whenever we change anything in our kinds directory. The SDK provides a command for this: grafana-app-sdk generate, but our project init also gave us a make target which will do the same thing, so you can run either. Here, I'm running the make target:

make generate

This command should ouput a list of all the files it writes:

$ make generate
 * Writing file pkg/generated/resource/issue/v1/issue_codec_gen.go
 * Writing file pkg/generated/resource/issue/v1/issue_metadata_gen.go
 * Writing file pkg/generated/resource/issue/v1/issue_object_gen.go
 * Writing file pkg/generated/resource/issue/v1/issue_schema_gen.go
 * Writing file pkg/generated/resource/issue/v1/issue_spec_gen.go
 * Writing file pkg/generated/resource/issue/v1/issue_status_gen.go
 * Writing file plugin/src/generated/issue/v1/issue_object_gen.ts
 * Writing file plugin/src/generated/issue/v1/types.metadata.gen.ts
 * Writing file plugin/src/generated/issue/v1/types.spec.gen.ts
 * Writing file plugin/src/generated/issue/v1/types.status.gen.ts
 * Writing file definitions/issue.issue-tracker-project.ext.grafana.com.json

That's a bunch of files written! Let's tree the directory to understand the structure a bit better.

$ tree .
.
├── Makefile
├── cmd
│   └── operator
├── definitions
│   └── issue.issue-tracker-project.ext.grafana.com.json
├── go.mod
├── go.sum
├── kinds
│   ├── cue.mod
│   │   └── module.cue
│   └── issue.cue
├── local
│   ├── Tiltfile
│   ├── additional
│   ├── config.yaml
│   ├── mounted-files
│   │   └── plugin
│   └── scripts
│       ├── cluster.sh
│       └── push_image.sh
├── pkg
│   └── generated
│       └── resource
│           └── issue
│               └── v1
│                   ├── issue_codec_gen.go
│                   ├── issue_metadata_gen.go
│                   ├── issue_object_gen.go
│                   ├── issue_schema_gen.go
│                   ├── issue_spec_gen.go
│                   └── issue_status_gen.go
└── plugin
    └── src
        └── generated
            └── issue
                └── v1
                    ├── issue_object_gen.ts
                    ├── types.metadata.gen.ts
                    ├── types.spec.gen.ts
                    └── types.status.gen.ts

21 directories, 20 files

So we can now see that all our generated go code lives in the pkg/generated package. Since our target was "resource", the generated code for issue is in the pkg/generated/resource package. Each resource-target kind then lives in a package defined by the name of the kind: in our case, that is issue. If we created another kind in our kinds directory called "foo", we'd see a pkg/generated/resource/foo directory.

If we had a separate kind which didn't have the apiResource field, we'd see a pkg/generated/models package directory. We'll see that later, in our follow-up, where we extend on the project.

Note that the go types are in versioned packages, as by default the SDK will generate types for each version of the kind.

Note that we also have generated TypeScript in our previously-empty plugin directory. By convention, the Grafana plugin for your project will live in the plugin directory, so here we've got some TypeScript generated in plugin/src/generated to use when we start working on the front-end of our plugin.

Generated Go Code

The package with the largest number of files generated by make generate is the pkg/generated/resource/issue package. This is also the package where all of our generated go code lives (even with multiple kinds, all generated go code will live in pkg/generated).

Let's take a closer look at the list of files:

$ tree pkg/generated
pkg/generated
└── resource
    └── issue
        └── v1
            ├── issue_codec_gen.go
            ├── issue_metadata_gen.go
            ├── issue_object_gen.go
            ├── issue_schema_gen.go
            ├── issue_spec_gen.go
            └── issue_status_gen.go

4 directories, 6 files

The exported go types from our kind's v1 schema definition are issue_spec_gen.go and issue_status_gen.go. issue_metadata_gen.go exists for legacy reasons we won't touch on here. You'll note that issue_status_gen.go contain types and fields which we didn't define in our schema--that's because of the joined "default" status information. If we had defined a status or metadata in our schema, those fields would also be present in the generated types.

In addition to the types generated from our kind's schema, we have issue_object_gen.go, issue_schema_gen.go, and issue_codec_gen.go. issue_object_gen.go defines the complete object (with spec, status, and metadata) in a way that satisfies the resource.Object interface, so that it can be used with the SDK. Likewise, issue_schema_gen.go defines a resource.Schema for this specific version of the kind which can be used in your project, in addition to a resource.Kind for the kind. Finally, issue_codec_gen.go contains code for a kubernetes-JSON-bytes<->Issue Object codec, which is used by the Kind for marshaling and unmarshaling our Object when interacting with the API server.

Generated TypeScript Code

$ tree plugin
plugin
└── src
    └── generated
        └── issue
            └── v1
                ├── issue_object_gen.ts
                ├── types.metadata.gen.ts
                ├── types.spec.gen.ts
                └── types.status.gen.ts

5 directories, 4 files

The generated TypeScript contains an interface built from our schema. Similarly to our go code, there are types for Spec and Status (and a legacy Metadata type), and an Object type which pulls them all together. TypeScript code is only generated for kinds where frontend: true.

Generated Custom Resource Definitions

Finally, we have the custom resource definition file that describes our issue kind as a CRD, which lives in definitions by default. Note that this is a CRD of the kind, not just the schema, so the CRD will contain all schema versions in the kind. This can be used to set up kubernetes as our storage layer for our project.

$ tree definitions
definitions
└── issue.issue-tracker-project.ext.grafana.com.json

1 directory, 1 file

So now we have a bunch of generated code, but we still need a project to actually use it in. The SDK gives us some tooling to set up our project with boilerplate code, so let's do that next.