Skip to content

Commit fdd44d5

Browse files
authored
feat: Add publish command (#1143)
As we are productionizing and rolling out our own registry we need to move from our format being documented in a yaml file inside goreleaser to being part of our code and part of the sdk. Right now this just build the package without publishing as our backend is not ready but nailing down this will also help finalize the backend which Im working on as well. The idea here is **not** to introduce a `package.json` file like in npm and then create yet another language inside `json` or `yaml` config but rather the other way around and use all the information we already have from the plugin author and build a package with a manifest.json so everything is configurable in the code. we will have two types of packages in our registry: - `native` (for languages like Go/Rust/C) - `docker` (for runtime language like .net, Java, Python) For native this will looks the following: ``` ls -l ./dist (base) yevgenyp@yevgenys-mbp aws % ls -l dist total 1142360 -rw-r--r-- 1 yevgenyp staff 447 Aug 13 20:08 plugin.json -rw-r--r-- 1 yevgenyp staff 145537822 Aug 13 20:08 plugin_darwin_amd64.zip -rw-r--r-- 1 yevgenyp staff 145537822 Aug 13 20:08 plugin_darwin_arm64.zip -rw-r--r-- 1 yevgenyp staff 145537820 Aug 13 20:07 plugin_linux_amd64.zip -rw-r--r-- 1 yevgenyp staff 145537824 Aug 13 20:07 plugin_windows_amd64.zip -rw-r--r-- 1 yevgenyp staff 2726434 Aug 13 20:07 tables.json (base) yevgenyp@yevgenys-mbp aws % ``` manifest will look the following: ``` cat plugin.json { "name": "aws", "version": "Development", "title": "aws", "short_description": "", "description": "", "categories": [], "protocols": [ 3 ], "supported_targets": [ { "os": "linux", "arch": "amd64" }, { "os": "windows", "arch": "amd64" }, { "os": "darwin", "arch": "amd64" }, { "os": "darwin", "arch": "arm64" } ], "package_type": "native" } ``` This will make sure the cloudquery package registry has all the information needed to publish it, display it on CloudQuery Hub and give it for client to download without running the plugins itself. Not running the plugin itself is important for the following reasons: - Security: not running untrusted code in our environment. - Developer experience: moving any issues closer to the developer and shortening the debugging/publishing loop. Once it gets a first review I'll also add tests.
1 parent 763c549 commit fdd44d5

File tree

18 files changed

+1196
-24
lines changed

18 files changed

+1196
-24
lines changed

examples/simple_plugin/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package client
2+
3+
import (
4+
"context"
5+
6+
"github.com/cloudquery/plugin-sdk/v4/schema"
7+
"github.com/rs/zerolog"
8+
)
9+
10+
type TestClient struct {
11+
Logger zerolog.Logger
12+
Spec Spec
13+
ClientID int
14+
}
15+
16+
func (*TestClient) ID() string {
17+
return "TestClient"
18+
}
19+
20+
func (c *TestClient) withClientID(i int) *TestClient {
21+
t := *c
22+
t.ClientID = i
23+
return &t
24+
}
25+
26+
func MultiplexBySpec(meta schema.ClientMeta) []schema.ClientMeta {
27+
cl := meta.(*TestClient)
28+
clients := make([]schema.ClientMeta, cl.Spec.NumClients)
29+
for i := 0; i < cl.Spec.NumClients; i++ {
30+
clients[i] = cl.withClientID(i)
31+
}
32+
return clients
33+
}
34+
35+
func ResolveClientID(_ context.Context, meta schema.ClientMeta, resource *schema.Resource, c schema.Column) error {
36+
cl := meta.(*TestClient)
37+
return resource.Set(c.Name, cl.ClientID)
38+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package client
2+
3+
type Spec struct {
4+
NumClients int `json:"num_clients"`
5+
}
6+
7+
func (s *Spec) SetDefaults() {
8+
if s.NumClients <= 0 {
9+
s.NumClients = 1
10+
}
11+
}
12+
13+
func (*Spec) Validate() error {
14+
return nil
15+
}

examples/simple_plugin/go.mod

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
module github.com/cloudquery/plugin-sdk/examples/simple_plugin
2+
3+
go 1.20
4+
5+
require (
6+
github.com/apache/arrow/go/v13 v13.0.0-20230731205701-112f94971882
7+
github.com/cloudquery/plugin-sdk/v4 v4.4.0
8+
github.com/rs/zerolog v1.30.0
9+
)
10+
11+
replace github.com/cloudquery/plugin-sdk/v4 => ../../
12+
13+
require (
14+
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
15+
github.com/cloudquery/plugin-pb-go v1.9.2 // indirect
16+
github.com/cloudquery/plugin-sdk/v2 v2.7.0 // indirect
17+
github.com/davecgh/go-spew v1.1.1 // indirect
18+
github.com/getsentry/sentry-go v0.20.0 // indirect
19+
github.com/ghodss/yaml v1.0.0 // indirect
20+
github.com/go-logr/logr v1.2.4 // indirect
21+
github.com/go-logr/stdr v1.2.2 // indirect
22+
github.com/goccy/go-json v0.10.2 // indirect
23+
github.com/golang/protobuf v1.5.3 // indirect
24+
github.com/google/flatbuffers v23.5.26+incompatible // indirect
25+
github.com/google/uuid v1.3.0 // indirect
26+
github.com/grpc-ecosystem/go-grpc-middleware/providers/zerolog/v2 v2.0.0-rc.3 // indirect
27+
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 // indirect
28+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
29+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
30+
github.com/klauspost/compress v1.16.7 // indirect
31+
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
32+
github.com/mattn/go-colorable v0.1.13 // indirect
33+
github.com/mattn/go-isatty v0.0.19 // indirect
34+
github.com/pierrec/lz4/v4 v4.1.18 // indirect
35+
github.com/pmezard/go-difflib v1.0.0 // indirect
36+
github.com/spf13/cobra v1.6.1 // indirect
37+
github.com/spf13/pflag v1.0.5 // indirect
38+
github.com/stretchr/testify v1.8.4 // indirect
39+
github.com/thoas/go-funk v0.9.3 // indirect
40+
github.com/zeebo/xxh3 v1.0.2 // indirect
41+
go.opentelemetry.io/otel v1.16.0 // indirect
42+
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect
43+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect
44+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 // indirect
45+
go.opentelemetry.io/otel/metric v1.16.0 // indirect
46+
go.opentelemetry.io/otel/sdk v1.16.0 // indirect
47+
go.opentelemetry.io/otel/trace v1.16.0 // indirect
48+
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
49+
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 // indirect
50+
golang.org/x/mod v0.11.0 // indirect
51+
golang.org/x/net v0.10.0 // indirect
52+
golang.org/x/sync v0.1.0 // indirect
53+
golang.org/x/sys v0.8.0 // indirect
54+
golang.org/x/text v0.9.0 // indirect
55+
golang.org/x/tools v0.6.0 // indirect
56+
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
57+
google.golang.org/genproto v0.0.0-20230731193218-e0aa005b6bdf // indirect
58+
google.golang.org/genproto/googleapis/api v0.0.0-20230731193218-e0aa005b6bdf // indirect
59+
google.golang.org/genproto/googleapis/rpc v0.0.0-20230731193218-e0aa005b6bdf // indirect
60+
google.golang.org/grpc v1.57.0 // indirect
61+
google.golang.org/protobuf v1.31.0 // indirect
62+
gopkg.in/yaml.v2 v2.4.0 // indirect
63+
gopkg.in/yaml.v3 v3.0.1 // indirect
64+
)

examples/simple_plugin/go.sum

Lines changed: 549 additions & 0 deletions
Large diffs are not rendered by default.

examples/simple_plugin/main.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"log"
6+
7+
"github.com/cloudquery/plugin-sdk/examples/simple_plugin/plugin"
8+
"github.com/cloudquery/plugin-sdk/v4/serve"
9+
)
10+
11+
func main() {
12+
p := serve.Plugin(plugin.Plugin())
13+
if err := p.Serve(context.Background()); err != nil {
14+
log.Fatalf("failed to serve plugin: %v", err)
15+
}
16+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package plugin
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
8+
"github.com/cloudquery/plugin-sdk/examples/simple_plugin/client"
9+
"github.com/cloudquery/plugin-sdk/examples/simple_plugin/services"
10+
"github.com/cloudquery/plugin-sdk/v4/message"
11+
"github.com/cloudquery/plugin-sdk/v4/plugin"
12+
"github.com/cloudquery/plugin-sdk/v4/scheduler"
13+
"github.com/cloudquery/plugin-sdk/v4/schema"
14+
"github.com/cloudquery/plugin-sdk/v4/transformers"
15+
"github.com/rs/zerolog"
16+
)
17+
18+
type Client struct {
19+
logger zerolog.Logger
20+
config client.Spec
21+
tables schema.Tables
22+
scheduler *scheduler.Scheduler
23+
24+
plugin.UnimplementedDestination
25+
}
26+
27+
func (c *Client) Logger() *zerolog.Logger {
28+
return &c.logger
29+
}
30+
31+
func (c *Client) Sync(ctx context.Context, options plugin.SyncOptions, res chan<- message.SyncMessage) error {
32+
tt, err := c.tables.FilterDfs(options.Tables, options.SkipTables, options.SkipDependentTables)
33+
if err != nil {
34+
return err
35+
}
36+
37+
schedulerClient := &client.TestClient{
38+
Logger: c.logger,
39+
Spec: c.config,
40+
}
41+
42+
return c.scheduler.Sync(ctx, schedulerClient, tt, res, scheduler.WithSyncDeterministicCQID(options.DeterministicCQID))
43+
}
44+
45+
func (c *Client) Tables(_ context.Context, options plugin.TableOptions) (schema.Tables, error) {
46+
tt, err := c.tables.FilterDfs(options.Tables, options.SkipTables, options.SkipDependentTables)
47+
if err != nil {
48+
return nil, err
49+
}
50+
51+
return tt, nil
52+
}
53+
54+
func (*Client) Close(_ context.Context) error {
55+
return nil
56+
}
57+
58+
func Configure(_ context.Context, logger zerolog.Logger, spec []byte, opts plugin.NewClientOptions) (plugin.Client, error) {
59+
if opts.NoConnection {
60+
return &Client{
61+
logger: logger,
62+
tables: getTables(),
63+
}, nil
64+
}
65+
66+
config := &client.Spec{}
67+
if err := json.Unmarshal(spec, config); err != nil {
68+
return nil, fmt.Errorf("failed to unmarshal spec: %w", err)
69+
}
70+
config.SetDefaults()
71+
if err := config.Validate(); err != nil {
72+
return nil, fmt.Errorf("failed to validate spec: %w", err)
73+
}
74+
75+
return &Client{
76+
logger: logger,
77+
config: *config,
78+
scheduler: scheduler.NewScheduler(
79+
scheduler.WithLogger(logger),
80+
),
81+
tables: getTables(),
82+
}, nil
83+
}
84+
85+
func getTables() schema.Tables {
86+
tables := schema.Tables{
87+
services.TestSomeTable(),
88+
}
89+
if err := transformers.TransformTables(tables); err != nil {
90+
panic(err)
91+
}
92+
for _, t := range tables {
93+
schema.AddCqIDs(t)
94+
}
95+
return tables
96+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package plugin
2+
3+
import (
4+
"github.com/cloudquery/plugin-sdk/v4/plugin"
5+
)
6+
7+
var (
8+
Version = "development"
9+
)
10+
11+
func Plugin() *plugin.Plugin {
12+
return plugin.NewPlugin(
13+
"test",
14+
Version,
15+
Configure,
16+
)
17+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package services
2+
3+
import (
4+
"context"
5+
6+
"github.com/apache/arrow/go/v13/arrow"
7+
"github.com/cloudquery/plugin-sdk/examples/simple_plugin/client"
8+
"github.com/cloudquery/plugin-sdk/v4/schema"
9+
)
10+
11+
func TestSomeTable() *schema.Table {
12+
return &schema.Table{
13+
Name: "test_some_table",
14+
Description: "Test description",
15+
Resolver: fetchSomeTableData,
16+
Multiplex: client.MultiplexBySpec,
17+
Columns: []schema.Column{
18+
{
19+
Name: "column1",
20+
Description: "Test Column 1",
21+
Type: arrow.BinaryTypes.String,
22+
PrimaryKey: true,
23+
Resolver: schema.PathResolver("column1"),
24+
},
25+
{
26+
Name: "column2",
27+
Description: "Test Column 2",
28+
Type: arrow.PrimitiveTypes.Int64,
29+
Resolver: schema.PathResolver("column2"),
30+
},
31+
{
32+
Name: "client_id",
33+
Description: "ID of client",
34+
Type: arrow.PrimitiveTypes.Int64,
35+
Resolver: client.ResolveClientID,
36+
PrimaryKey: true,
37+
},
38+
},
39+
}
40+
}
41+
42+
func fetchSomeTableData(ctx context.Context, meta schema.ClientMeta, parent *schema.Resource, res chan<- any) error {
43+
res <- map[string]any{
44+
"column1": "test_project_id",
45+
"column2": 123,
46+
}
47+
return nil
48+
}
26.1 MB
Binary file not shown.

0 commit comments

Comments
 (0)