Skip to content

Commit 3b5def0

Browse files
authored
feat(plugins SDK): implement go-plugin framework (#207)
Signed-off-by: Miguel Martinez Trivino <[email protected]>
1 parent 53efa31 commit 3b5def0

39 files changed

+3255
-144
lines changed

.goreleaser.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ builds:
2828
- darwin_arm64
2929
- linux_amd64
3030
- linux_arm64
31+
# Plugins build
32+
# NOTE: On the event of a new plugin added to the project you need to
33+
# 1 - Add the plugins binary to be built in this section
34+
# 2 - Add the plugin ID to the allow-list in the dockers.IDs section
35+
# 3 - Update the Dockerfile.goreleaser
36+
- binary: chainloop-plugin-discord-webhook
37+
id: chainloop-plugin-discord-webhook
38+
main: ./app/controlplane/plugins/core/discord-webhook/v1/cmd
39+
targets:
40+
- linux_amd64
3141
archives:
3242
- builds:
3343
- cli
@@ -62,6 +72,7 @@ dockers:
6272
- dockerfile: app/controlplane/Dockerfile.goreleaser
6373
ids:
6474
- control-plane
75+
- chainloop-plugin-discord-webhook
6576
image_templates:
6677
- "ghcr.io/chainloop-dev/chainloop/control-plane:{{ .Tag }}"
6778
- "ghcr.io/chainloop-dev/chainloop/control-plane:latest"

Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,12 @@ lint:
4242
# All tests, both unit and integration
4343
test:
4444
go test ./...
45+
46+
.PHONY: build_devel
47+
# build for development testing
48+
build_devel:
49+
goreleaser build --snapshot --clean --single-target
50+
.PHONY: build_devel_container_mages
51+
# build container images for development testing
52+
build_devel_container_mages:
53+
goreleaser release --clean --snapshot --skip-sign --skip-sbom

app/controlplane/Dockerfile.goreleaser

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@ FROM golang:1.20 AS builder
22

33
FROM scratch
44

5-
COPY ./control-plane /
65
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
76

7+
COPY ./control-plane /
8+
# Add plugins here
9+
# NOTE: they are built by go-releaser in the builds section
10+
# Make sure to update it acordingly if you add more plugins
11+
COPY ./chainloop-plugin-discord-webhook /plugins/
12+
# tmp is required for the plugins to run
13+
COPY --from=builder /tmp /tmp
14+
815
ENTRYPOINT [ "/control-plane", "--conf", "/data/conf"]

app/controlplane/cmd/main.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
"github.com/chainloop-dev/chainloop/app/controlplane/internal/biz"
2727
"github.com/chainloop-dev/chainloop/app/controlplane/internal/conf"
2828
"github.com/chainloop-dev/chainloop/app/controlplane/internal/server"
29+
"github.com/chainloop-dev/chainloop/app/controlplane/plugins"
30+
"github.com/chainloop-dev/chainloop/app/controlplane/plugins/sdk/v1"
2931
credsConfig "github.com/chainloop-dev/chainloop/internal/credentials/api/credentials/v1"
3032
"github.com/chainloop-dev/chainloop/internal/servicelogger"
3133

@@ -54,7 +56,7 @@ func init() {
5456
flag.StringVar(&flagconf, "conf", "../configs", "config path, eg: -conf config.yaml")
5557
}
5658

57-
func newApp(logger log.Logger, gs *grpc.Server, hs *http.Server, ms *server.HTTPMetricsServer, expirer *biz.WorkflowRunExpirerUseCase) *app {
59+
func newApp(logger log.Logger, gs *grpc.Server, hs *http.Server, ms *server.HTTPMetricsServer, expirer *biz.WorkflowRunExpirerUseCase, plugins sdk.AvailablePlugins) *app {
5860
return &app{
5961
kratos.New(
6062
kratos.ID(id),
@@ -63,7 +65,7 @@ func newApp(logger log.Logger, gs *grpc.Server, hs *http.Server, ms *server.HTTP
6365
kratos.Metadata(map[string]string{}),
6466
kratos.Logger(logger),
6567
kratos.Server(gs, hs, ms),
66-
), expirer}
68+
), expirer, plugins}
6769
}
6870

6971
func main() {
@@ -72,7 +74,7 @@ func main() {
7274
config.WithSource(
7375
file.NewSource(flagconf),
7476
// Load environments variables prefixed with CP_
75-
// NOTE: They get resolved withouth the prefix, i.e CP_DB_HOST -> DB_HOST
77+
// NOTE: They get resolved without the prefix, i.e CP_DB_HOST -> DB_HOST
7678
env.NewSource("CP_"),
7779
),
7880
)
@@ -105,7 +107,15 @@ func main() {
105107
panic(err)
106108
}
107109

108-
app, cleanup, err := wireApp(&bc, credsWriter, logger)
110+
// Load plugins
111+
availablePlugins, err := plugins.Load(bc.GetPluginsDir(), logger)
112+
if err != nil {
113+
panic(err)
114+
}
115+
// Kill plugins processes on exit
116+
defer availablePlugins.Cleanup()
117+
118+
app, cleanup, err := wireApp(&bc, credsWriter, logger, availablePlugins)
109119
if err != nil {
110120
panic(err)
111121
}
@@ -127,7 +137,8 @@ func main() {
127137
type app struct {
128138
*kratos.App
129139
// Periodic job that expires unfinished attestation processes older than a given threshold
130-
runsExpirer *biz.WorkflowRunExpirerUseCase
140+
runsExpirer *biz.WorkflowRunExpirerUseCase
141+
availablePlugins sdk.AvailablePlugins
131142
}
132143

133144
func filterSensitiveArgs(_ log.Level, keyvals ...interface{}) bool {

app/controlplane/cmd/wire.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ import (
2727
"github.com/chainloop-dev/chainloop/app/controlplane/internal/dispatcher"
2828
"github.com/chainloop-dev/chainloop/app/controlplane/internal/server"
2929
"github.com/chainloop-dev/chainloop/app/controlplane/internal/service"
30-
"github.com/chainloop-dev/chainloop/app/controlplane/plugins"
30+
"github.com/chainloop-dev/chainloop/app/controlplane/plugins/sdk/v1"
3131
backend "github.com/chainloop-dev/chainloop/internal/blobmanager"
3232
"github.com/chainloop-dev/chainloop/internal/blobmanager/oci"
3333
"github.com/chainloop-dev/chainloop/internal/credentials"
3434
"github.com/go-kratos/kratos/v2/log"
3535
"github.com/google/wire"
3636
)
3737

38-
func wireApp(*conf.Bootstrap, credentials.ReaderWriter, log.Logger) (*app, func(), error) {
38+
func wireApp(*conf.Bootstrap, credentials.ReaderWriter, log.Logger, sdk.AvailablePlugins) (*app, func(), error) {
3939
panic(
4040
wire.Build(
4141
wire.Bind(new(credentials.Reader), new(credentials.ReaderWriter)),
@@ -49,7 +49,6 @@ func wireApp(*conf.Bootstrap, credentials.ReaderWriter, log.Logger) (*app, func(
4949
serviceOpts,
5050
wire.Value([]biz.CASClientOpts{}),
5151
wire.FieldsOf(new(*conf.Bootstrap), "Server", "Auth", "Data", "CasServer"),
52-
plugins.Load,
5352
dispatcher.New,
5453
newApp,
5554
),

app/controlplane/cmd/wire_gen.go

Lines changed: 3 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/configs/config.devel.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ server:
1313
# We have some slow operations such as verifying an OCI registry
1414
timeout: 10s
1515

16+
# Directory where the plugins are located
17+
# NOTE: plugins have the form of chainloop-plugin-<name>
18+
plugins_dir: "./plugins/bin"
1619
# Local CAS server for development
1720
cas_server:
1821
grpc:

app/controlplane/internal/biz/testhelpers/database.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ func WithCredsReaderWriter(rw credentials.ReaderWriter) NewTestingUCOpt {
7979
func WithRegisteredIntegration(i sdk.FanOut) NewTestingUCOpt {
8080
return func(tu *newTestingOpts) {
8181
if tu.integrations == nil {
82-
tu.integrations = []sdk.FanOut{i}
82+
tu.integrations = []*sdk.FanOutP{{FanOut: i}}
8383
} else {
84-
tu.integrations = append(tu.integrations, i)
84+
tu.integrations = append(tu.integrations, &sdk.FanOutP{FanOut: i})
8585
}
8686
}
8787
}

0 commit comments

Comments
 (0)