From c5312c87b8a1f9381c25376454885c2e94265ec5 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 17:29:43 +0100 Subject: [PATCH 01/15] Place field in correct order --- plugin/v1/plugin.pb.go | 28 ++++++++++++++-------------- plugin/v1/plugin.proto | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/plugin/v1/plugin.pb.go b/plugin/v1/plugin.pb.go index 83999d16..e8e83776 100644 --- a/plugin/v1/plugin.pb.go +++ b/plugin/v1/plugin.pb.go @@ -186,9 +186,9 @@ type PluginConfig struct { Id *PluginID `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + Authors []string `protobuf:"bytes,3,rep,name=authors,proto3" json:"authors,omitempty"` License string `protobuf:"bytes,4,opt,name=license,proto3" json:"license,omitempty"` ProjectUrl string `protobuf:"bytes,5,opt,name=project_url,json=projectUrl,proto3" json:"project_url,omitempty"` - Authors []string `protobuf:"bytes,3,rep,name=authors,proto3" json:"authors,omitempty"` // internal and external config options Config map[string]string `protobuf:"bytes,6,rep,name=config,proto3" json:"config,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // hooks it attaches to @@ -245,6 +245,13 @@ func (x *PluginConfig) GetDescription() string { return "" } +func (x *PluginConfig) GetAuthors() []string { + if x != nil { + return x.Authors + } + return nil +} + func (x *PluginConfig) GetLicense() string { if x != nil { return x.License @@ -259,13 +266,6 @@ func (x *PluginConfig) GetProjectUrl() string { return "" } -func (x *PluginConfig) GetAuthors() []string { - if x != nil { - return x.Authors - } - return nil -} - func (x *PluginConfig) GetConfig() map[string]string { if x != nil { return x.Config @@ -330,12 +330,12 @@ var file_plugin_v1_plugin_proto_rawDesc = []byte{ 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, - 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x72, - 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x12, 0x3b, 0x0a, 0x06, 0x63, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, + 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x72, 0x6c, 0x12, 0x3b, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, diff --git a/plugin/v1/plugin.proto b/plugin/v1/plugin.proto index cda0ef7a..cef887e0 100644 --- a/plugin/v1/plugin.proto +++ b/plugin/v1/plugin.proto @@ -51,9 +51,9 @@ message PluginID { message PluginConfig { PluginID id = 1; string description = 2; + repeated string authors = 3; string license = 4; string project_url = 5; - repeated string authors = 3; // internal and external config options map config = 6; // hooks it attaches to From ac919fe911c5b4be75f679c56e9a886386469366 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 17:33:14 +0100 Subject: [PATCH 02/15] Fix data type error --- cmd/run.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/run.go b/cmd/run.go index f3fac2e6..cfe7d4ad 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -136,10 +136,10 @@ var runCmd = &cobra.Command{ "address": clientConfig.Address, "receiveBufferSize": clientConfig.ReceiveBufferSize, "receiveChunkSize": clientConfig.ReceiveChunkSize, - "receiveDeadline": clientConfig.ReceiveDeadline, - "sendDeadline": clientConfig.SendDeadline, + "receiveDeadline": clientConfig.ReceiveDeadline.Seconds(), + "sendDeadline": clientConfig.SendDeadline.Seconds(), "tcpKeepAlive": clientConfig.TCPKeepAlive, - "tcpKeepAlivePeriod": clientConfig.TCPKeepAlivePeriod, + "tcpKeepAlivePeriod": clientConfig.TCPKeepAlivePeriod.Seconds(), } _, err := hooksConfig.Run( context.Background(), From 5dc79579e4820b7eeb2ed5c4456183418c15bc71 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 17:33:30 +0100 Subject: [PATCH 03/15] Update package checksum --- gatewayd_plugins.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gatewayd_plugins.yaml b/gatewayd_plugins.yaml index 42e5ec4e..b8f20abc 100644 --- a/gatewayd_plugins.yaml +++ b/gatewayd_plugins.yaml @@ -17,4 +17,4 @@ gatewayd-plugin-test: - MAGIC_COOKIE_KEY=GATEWAYD_PLUGIN - MAGIC_COOKIE_VALUE=5712b87aa5d7e9f9e9ab643e6603181c5b796015cb1c09d6f5ada882bf2a1872 # Checksum hash to verify the binary before loading - checksum: 006e19bcfd1951e077746143590934470e8b1d67a3904036603013e150fcb708 + checksum: 0cbc4eb8859cac70644c582c85fa20822cffb39599e00b76178fc4f8d37b508c From 25943375898a311d9af37adf41d1c5d22e508dfe Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 17:44:02 +0100 Subject: [PATCH 04/15] Check requires field as soon as the plugin is started to check requirements --- plugin/registry.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/plugin/registry.go b/plugin/registry.go index dadba103..b5182e48 100644 --- a/plugin/registry.go +++ b/plugin/registry.go @@ -209,15 +209,23 @@ func (reg *RegistryImpl) LoadPlugins(pluginConfig *koanf.Koanf) { } } + if err := mapstructure.Decode(metadata.Fields["requires"].GetListValue().AsSlice(), + &plugin.Requires); err != nil { + reg.hooksConfig.Logger.Debug().Err(err).Msg("Failed to decode plugin requirements") + } + + for _, req := range plugin.Requires { + if reg.Get(req) == nil { + reg.hooksConfig.Logger.Debug().Str("name", plugin.ID.Name).Msg( + "The plugin requirement is not met, so it won't work properly") + } + } + plugin.ID.RemoteURL = metadata.Fields["id"].GetStructValue().Fields["remoteUrl"].GetStringValue() plugin.ID.Version = metadata.Fields["id"].GetStructValue().Fields["version"].GetStringValue() plugin.Description = metadata.Fields["description"].GetStringValue() plugin.License = metadata.Fields["license"].GetStringValue() plugin.ProjectURL = metadata.Fields["projectUrl"].GetStringValue() - if err := mapstructure.Decode(metadata.Fields["requires"].GetListValue().AsSlice(), - &plugin.Requires); err != nil { - reg.hooksConfig.Logger.Debug().Err(err).Msg("Failed to decode plugin requirements") - } if err := mapstructure.Decode(metadata.Fields["authors"].GetListValue().AsSlice(), &plugin.Authors); err != nil { reg.hooksConfig.Logger.Debug().Err(err).Msg("Failed to decode plugin authors") From 792986f0a13d7dfe4cc0ba02bcffe9220fc55b12 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 17:46:27 +0100 Subject: [PATCH 05/15] Add comments --- plugin/registry.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugin/registry.go b/plugin/registry.go index b5182e48..dda2a8a9 100644 --- a/plugin/registry.go +++ b/plugin/registry.go @@ -209,11 +209,13 @@ func (reg *RegistryImpl) LoadPlugins(pluginConfig *koanf.Koanf) { } } + // Retrieve plugin requirements. if err := mapstructure.Decode(metadata.Fields["requires"].GetListValue().AsSlice(), &plugin.Requires); err != nil { reg.hooksConfig.Logger.Debug().Err(err).Msg("Failed to decode plugin requirements") } + // Check if the plugin requirements are met. for _, req := range plugin.Requires { if reg.Get(req) == nil { reg.hooksConfig.Logger.Debug().Str("name", plugin.ID.Name).Msg( @@ -226,15 +228,18 @@ func (reg *RegistryImpl) LoadPlugins(pluginConfig *koanf.Koanf) { plugin.Description = metadata.Fields["description"].GetStringValue() plugin.License = metadata.Fields["license"].GetStringValue() plugin.ProjectURL = metadata.Fields["projectUrl"].GetStringValue() + // Retrieve authors. if err := mapstructure.Decode(metadata.Fields["authors"].GetListValue().AsSlice(), &plugin.Authors); err != nil { reg.hooksConfig.Logger.Debug().Err(err).Msg("Failed to decode plugin authors") } + // Retrieve hooks. if err := mapstructure.Decode(metadata.Fields["hooks"].GetListValue().AsSlice(), &plugin.Hooks); err != nil { reg.hooksConfig.Logger.Debug().Err(err).Msg("Failed to decode plugin hooks") } + // Retrieve plugin config. plugin.Config = make(map[string]string) for key, value := range metadata.Fields["config"].GetStructValue().AsMap() { if val, ok := value.(string); ok { From deee8cead14ce3d1445d56da9b4bb9e498bf3e08 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 18:25:05 +0100 Subject: [PATCH 06/15] Add semver/v3 dependency --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index 95a36d20..8aa44d8a 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/gatewayd-io/gatewayd go 1.19 require ( + github.com/Masterminds/semver/v3 v3.2.0 github.com/fergusstrange/embedded-postgres v1.19.0 github.com/google/go-cmp v0.5.9 github.com/hashicorp/go-hclog v1.4.0 diff --git a/go.sum b/go.sum index 27623ff7..d39b3823 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= From 3c8eb73ac80c6b3cb7cc296e8ac6ef10fdf697f0 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 18:25:52 +0100 Subject: [PATCH 07/15] Add Exists function to verify if a given plugin exists in the registry and its version is less than or equal to the supplied plugin --- plugin/registry.go | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/plugin/registry.go b/plugin/registry.go index dda2a8a9..3730e475 100644 --- a/plugin/registry.go +++ b/plugin/registry.go @@ -3,6 +3,7 @@ package plugin import ( "context" + semver "github.com/Masterminds/semver/v3" gerr "github.com/gatewayd-io/gatewayd/errors" "github.com/gatewayd-io/gatewayd/logging" pluginV1 "github.com/gatewayd-io/gatewayd/plugin/v1" @@ -25,6 +26,7 @@ type Registry interface { Add(plugin *Impl) bool Get(id Identifier) *Impl List() []Identifier + Exists(name, version, remoteUrl string) bool Remove(id Identifier) Shutdown() LoadPlugins(pluginConfig *koanf.Koanf) @@ -74,6 +76,41 @@ func (reg *RegistryImpl) List() []Identifier { return plugins } +// Exists checks if a plugin exists in the registry. +func (reg *RegistryImpl) Exists(name, version, remoteUrl string) bool { + for _, plugin := range reg.List() { + if plugin.Name == name && plugin.RemoteURL == remoteUrl { + // Parse the supplied version and the version in the registry. + suppliedVer, err := semver.NewVersion(version) + if err != nil { + reg.hooksConfig.Logger.Error().Err(err).Msg( + "Failed to parse supplied plugin version") + return false + } + + registryVer, err := semver.NewVersion(plugin.Version) + if err != nil { + reg.hooksConfig.Logger.Error().Err(err).Msg( + "Failed to parse plugin version in registry") + return false + } + + // Check if the version of the plugin is less than or equal to + // the version in the registry. + if suppliedVer.LessThan(registryVer) || suppliedVer.Equal(registryVer) { + return true + } else { + reg.hooksConfig.Logger.Debug().Str("name", name).Str("version", version).Msg( + "Supplied plugin version is greater than the version in registry") + return false + } + } + return false + } + + return false +} + // Remove removes a plugin from the registry. func (reg *RegistryImpl) Remove(id Identifier) { reg.plugins.Remove(id) @@ -215,9 +252,16 @@ func (reg *RegistryImpl) LoadPlugins(pluginConfig *koanf.Koanf) { reg.hooksConfig.Logger.Debug().Err(err).Msg("Failed to decode plugin requirements") } + // Too many requirements or not enough plugins loaded. + if len(plugin.Requires) > reg.plugins.Size() { + reg.hooksConfig.Logger.Debug().Msg( + "The plugin has too many requirements, " + + "and not enough of them exist in the registry, so it won't work properly") + } + // Check if the plugin requirements are met. for _, req := range plugin.Requires { - if reg.Get(req) == nil { + if !reg.Exists(req.Name, req.Version, req.RemoteURL) { reg.hooksConfig.Logger.Debug().Str("name", plugin.ID.Name).Msg( "The plugin requirement is not met, so it won't work properly") } From 7651e63c201348b8fc4439cfbcbd59ed68dee256 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 18:26:50 +0100 Subject: [PATCH 08/15] Remove unnecessary return --- plugin/registry.go | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin/registry.go b/plugin/registry.go index 3730e475..e27b3030 100644 --- a/plugin/registry.go +++ b/plugin/registry.go @@ -105,7 +105,6 @@ func (reg *RegistryImpl) Exists(name, version, remoteUrl string) bool { return false } } - return false } return false From 9b3d98a05fca4dc5a8146a6962009cee6cf7a4db Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 18:40:02 +0100 Subject: [PATCH 09/15] Add compatibility policy to allow loading plugins without requirements --- plugin/registry.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/plugin/registry.go b/plugin/registry.go index e27b3030..56d0343b 100644 --- a/plugin/registry.go +++ b/plugin/registry.go @@ -14,6 +14,8 @@ import ( "google.golang.org/protobuf/types/known/structpb" ) +type PluginCompatPolicy uint + const ( DefaultMinPort uint = 50000 DefaultMaxPort uint = 60000 @@ -22,6 +24,11 @@ const ( LoggerName string = "plugin" ) +const ( + Strict PluginCompatPolicy = iota + Loose +) + type Registry interface { Add(plugin *Impl) bool Get(id Identifier) *Impl @@ -34,8 +41,9 @@ type Registry interface { } type RegistryImpl struct { - plugins pool.Pool - hooksConfig *HookConfig + plugins pool.Pool + hooksConfig *HookConfig + CompatPolicy PluginCompatPolicy } var _ Registry = &RegistryImpl{} @@ -263,6 +271,16 @@ func (reg *RegistryImpl) LoadPlugins(pluginConfig *koanf.Koanf) { if !reg.Exists(req.Name, req.Version, req.RemoteURL) { reg.hooksConfig.Logger.Debug().Str("name", plugin.ID.Name).Msg( "The plugin requirement is not met, so it won't work properly") + if reg.CompatPolicy == Strict { + reg.hooksConfig.Logger.Debug().Str("name", plugin.ID.Name).Msg( + "Registry is in strict compatibility mode, so the plugin won't be loaded") + plugin.Stop() // Stop the plugin. + continue + } else { + reg.hooksConfig.Logger.Debug().Str("name", plugin.ID.Name).Msg( + "Registry is in loose compatibility mode, " + + "so the plugin will be loaded anyway") + } } } From c5fb100fe0ad593ad9f006e21a819f16afbd02c1 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 18:51:28 +0100 Subject: [PATCH 10/15] End comments with a dot --- cmd/config_parser.go | 2 +- cmd/run.go | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cmd/config_parser.go b/cmd/config_parser.go index 75892c29..325b2dbe 100644 --- a/cmd/config_parser.go +++ b/cmd/config_parser.go @@ -36,7 +36,7 @@ func getPath(path string) string { // return nil // } -// verificationPolicy returns the verification policy for the plugin from config file. +// verificationPolicy returns the hook verification policy from plugin config file. func verificationPolicy() plugin.Policy { vPolicy := globalConfig.String("plugins.verificationPolicy") verificationPolicy := plugin.PassDown // default diff --git a/cmd/run.go b/cmd/run.go index cfe7d4ad..f1fd2de2 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -68,7 +68,7 @@ var runCmd = &cobra.Command{ } } - // Get hooks signature verification policy + // Get hooks signature verification policy. hooksConfig.Verification = verificationPolicy() // The config will be passed to the hooks, and in turn to the plugins that @@ -91,11 +91,11 @@ var runCmd = &cobra.Command{ } } - // Create a new logger from the config + // Create a new logger from the config. loggerCfg := loggerConfig() logger := logging.NewLogger(loggerCfg) - // Replace the default logger with the new one from the config + // Replace the default logger with the new one from the config. hooksConfig.Logger = logger // This is a notification hook, so we don't care about the result. @@ -111,7 +111,7 @@ var runCmd = &cobra.Command{ logger.Error().Err(err).Msg("Failed to run OnNewLogger hooks") } - // Create and initialize a pool of connections + // Create and initialize a pool of connections. poolSize, clientConfig := poolConfig() pool := pool.NewPool(poolSize) @@ -178,7 +178,7 @@ var runCmd = &cobra.Command{ logger.Error().Err(err).Msg("Failed to run OnNewPool hooks") } - // Create a prefork proxy with the pool of clients + // Create a prefork proxy with the pool of clients. elastic, reuseElasticClients, elasticClientConfig := proxyConfig() proxy := network.NewProxy( pool, hooksConfig, elastic, reuseElasticClients, elasticClientConfig, logger) @@ -266,7 +266,7 @@ var runCmd = &cobra.Command{ logger.Error().Err(err).Msg("Failed to run OnNewServer hooks") } - // Shutdown the server gracefully + // Shutdown the server gracefully. var signals []os.Signal signals = append(signals, os.Interrupt, @@ -283,7 +283,7 @@ var runCmd = &cobra.Command{ for sig := range signalsCh { for _, s := range signals { if sig != s { - // Notify the hooks that the server is shutting down + // Notify the hooks that the server is shutting down. _, err := hooksConfig.Run( context.Background(), map[string]interface{}{"signal": sig.String()}, @@ -302,7 +302,7 @@ var runCmd = &cobra.Command{ } }(hooksConfig) - // Run the server + // Run the server. if err := server.Run(); err != nil { logger.Error().Err(err).Msg("Failed to start server") } From 1dc2dcfe74cc83b11613fe6658da8c20053baf6c Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 18:53:57 +0100 Subject: [PATCH 11/15] Extract plugin compatibility policy from plugin config file --- cmd/config_parser.go | 14 ++++++++++++++ cmd/run.go | 5 ++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/cmd/config_parser.go b/cmd/config_parser.go index 325b2dbe..1d3bf703 100644 --- a/cmd/config_parser.go +++ b/cmd/config_parser.go @@ -52,6 +52,20 @@ func verificationPolicy() plugin.Policy { return verificationPolicy } +// pluginCompatPolicy returns the plugin compatibility policy from plugin config file. +func pluginCompatPolicy() plugin.PluginCompatPolicy { + vPolicy := pluginConfig.String("plugins.compatibilityPolicy") + compatPolicy := plugin.Strict // default + switch vPolicy { + case "strict": + compatPolicy = plugin.Strict + case "loose": + compatPolicy = plugin.Loose + } + + return compatPolicy +} + // loggerConfig returns the logger config from config file. func loggerConfig() logging.LoggerConfig { cfg := logging.LoggerConfig{StartupMsg: true} diff --git a/cmd/run.go b/cmd/run.go index f1fd2de2..01563af4 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -57,7 +57,10 @@ var runCmd = &cobra.Command{ } } - // Load plugins and register their hooks + // Set the plugin compatibility policy. + pluginRegistry.CompatPolicy = pluginCompatPolicy() + + // Load plugins and register their hooks. pluginRegistry.LoadPlugins(pluginConfig) if f, err := cmd.Flags().GetString("config"); err == nil { From 6b68355b32b9f1b907f95efd192c21ac69180b29 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 18:54:23 +0100 Subject: [PATCH 12/15] Move plugins config to plugin config file --- cmd/config_parser.go | 2 +- gatewayd.yaml | 3 --- gatewayd_plugins.yaml | 6 ++++++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cmd/config_parser.go b/cmd/config_parser.go index 1d3bf703..b6591606 100644 --- a/cmd/config_parser.go +++ b/cmd/config_parser.go @@ -38,7 +38,7 @@ func getPath(path string) string { // verificationPolicy returns the hook verification policy from plugin config file. func verificationPolicy() plugin.Policy { - vPolicy := globalConfig.String("plugins.verificationPolicy") + vPolicy := pluginConfig.String("plugins.verificationPolicy") verificationPolicy := plugin.PassDown // default switch vPolicy { case "ignore": diff --git a/gatewayd.yaml b/gatewayd.yaml index 27ddba4f..295089dc 100644 --- a/gatewayd.yaml +++ b/gatewayd.yaml @@ -65,6 +65,3 @@ server: reusePort: True tcpKeepAlive: 3s # duration tcpNoDelay: True - -plugins: - verificationPolicy: "passdown" diff --git a/gatewayd_plugins.yaml b/gatewayd_plugins.yaml index b8f20abc..6c4cab73 100644 --- a/gatewayd_plugins.yaml +++ b/gatewayd_plugins.yaml @@ -1,5 +1,11 @@ # Plugin configuration file for GatewayD +plugins: + # Possible values: "passdown" (default), "ignore", "abort" and "remove" + verificationPolicy: "passdown" + # Possible values: "strict" (default) and "loose" + compatibilityPolicy: "strict" + # Plugin name gatewayd-plugin-test: # whether to enable or disable the plugin on the next run From 7bf4ea7580e4a711e19c33f5a58b470c686b4a8b Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 18:58:24 +0100 Subject: [PATCH 13/15] Skip plugins top-level key --- plugin/registry.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugin/registry.go b/plugin/registry.go index 56d0343b..b3424e42 100644 --- a/plugin/registry.go +++ b/plugin/registry.go @@ -149,6 +149,11 @@ func (reg *RegistryImpl) LoadPlugins(pluginConfig *koanf.Koanf) { // Add each plugin to the registry. for priority, name := range plugins { + // Skip the top-level "plugins" key. + if name == "plugins" { + continue + } + reg.hooksConfig.Logger.Debug().Str("name", name).Msg("Loading plugin") plugin := &Impl{ ID: Identifier{ From b476f1937b6a3a5b7628a0a90edf897301802587 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 19:04:38 +0100 Subject: [PATCH 14/15] Add requirement name to the log Update plugin checksum --- gatewayd_plugins.yaml | 2 +- plugin/registry.go | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/gatewayd_plugins.yaml b/gatewayd_plugins.yaml index 6c4cab73..c175f664 100644 --- a/gatewayd_plugins.yaml +++ b/gatewayd_plugins.yaml @@ -23,4 +23,4 @@ gatewayd-plugin-test: - MAGIC_COOKIE_KEY=GATEWAYD_PLUGIN - MAGIC_COOKIE_VALUE=5712b87aa5d7e9f9e9ab643e6603181c5b796015cb1c09d6f5ada882bf2a1872 # Checksum hash to verify the binary before loading - checksum: 0cbc4eb8859cac70644c582c85fa20822cffb39599e00b76178fc4f8d37b508c + checksum: 09bce5ad90a36a6f3ec0804023098519424289f3d68679159d68e0b08ce70c89 diff --git a/plugin/registry.go b/plugin/registry.go index b3424e42..6cbae0ae 100644 --- a/plugin/registry.go +++ b/plugin/registry.go @@ -274,17 +274,25 @@ func (reg *RegistryImpl) LoadPlugins(pluginConfig *koanf.Koanf) { // Check if the plugin requirements are met. for _, req := range plugin.Requires { if !reg.Exists(req.Name, req.Version, req.RemoteURL) { - reg.hooksConfig.Logger.Debug().Str("name", plugin.ID.Name).Msg( - "The plugin requirement is not met, so it won't work properly") + reg.hooksConfig.Logger.Debug().Fields( + map[string]interface{}{ + "name": plugin.ID.Name, + "requirement": req.Name, + }, + ).Msg("The plugin requirement is not met, so it won't work properly") if reg.CompatPolicy == Strict { reg.hooksConfig.Logger.Debug().Str("name", plugin.ID.Name).Msg( "Registry is in strict compatibility mode, so the plugin won't be loaded") plugin.Stop() // Stop the plugin. continue } else { - reg.hooksConfig.Logger.Debug().Str("name", plugin.ID.Name).Msg( - "Registry is in loose compatibility mode, " + - "so the plugin will be loaded anyway") + reg.hooksConfig.Logger.Debug().Fields( + map[string]interface{}{ + "name": plugin.ID.Name, + "requirement": req.Name, + }, + ).Msg("Registry is in loose compatibility mode, " + + "so the plugin will be loaded anyway") } } } From a37aeb5a398a9e817e2e707c05f9a7a0f9e6cbb0 Mon Sep 17 00:00:00 2001 From: Mostafa Moradian Date: Wed, 4 Jan 2023 19:09:55 +0100 Subject: [PATCH 15/15] Fix linter errors --- cmd/config_parser.go | 2 +- plugin/registry.go | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/config_parser.go b/cmd/config_parser.go index b6591606..f1768830 100644 --- a/cmd/config_parser.go +++ b/cmd/config_parser.go @@ -53,7 +53,7 @@ func verificationPolicy() plugin.Policy { } // pluginCompatPolicy returns the plugin compatibility policy from plugin config file. -func pluginCompatPolicy() plugin.PluginCompatPolicy { +func pluginCompatPolicy() plugin.CompatPolicy { vPolicy := pluginConfig.String("plugins.compatibilityPolicy") compatPolicy := plugin.Strict // default switch vPolicy { diff --git a/plugin/registry.go b/plugin/registry.go index 6cbae0ae..159ba0b9 100644 --- a/plugin/registry.go +++ b/plugin/registry.go @@ -14,7 +14,7 @@ import ( "google.golang.org/protobuf/types/known/structpb" ) -type PluginCompatPolicy uint +type CompatPolicy uint const ( DefaultMinPort uint = 50000 @@ -25,7 +25,7 @@ const ( ) const ( - Strict PluginCompatPolicy = iota + Strict CompatPolicy = iota Loose ) @@ -33,7 +33,7 @@ type Registry interface { Add(plugin *Impl) bool Get(id Identifier) *Impl List() []Identifier - Exists(name, version, remoteUrl string) bool + Exists(name, version, remoteURL string) bool Remove(id Identifier) Shutdown() LoadPlugins(pluginConfig *koanf.Koanf) @@ -43,7 +43,7 @@ type Registry interface { type RegistryImpl struct { plugins pool.Pool hooksConfig *HookConfig - CompatPolicy PluginCompatPolicy + CompatPolicy CompatPolicy } var _ Registry = &RegistryImpl{} @@ -85,9 +85,9 @@ func (reg *RegistryImpl) List() []Identifier { } // Exists checks if a plugin exists in the registry. -func (reg *RegistryImpl) Exists(name, version, remoteUrl string) bool { +func (reg *RegistryImpl) Exists(name, version, remoteURL string) bool { for _, plugin := range reg.List() { - if plugin.Name == name && plugin.RemoteURL == remoteUrl { + if plugin.Name == name && plugin.RemoteURL == remoteURL { // Parse the supplied version and the version in the registry. suppliedVer, err := semver.NewVersion(version) if err != nil { @@ -107,11 +107,11 @@ func (reg *RegistryImpl) Exists(name, version, remoteUrl string) bool { // the version in the registry. if suppliedVer.LessThan(registryVer) || suppliedVer.Equal(registryVer) { return true - } else { - reg.hooksConfig.Logger.Debug().Str("name", name).Str("version", version).Msg( - "Supplied plugin version is greater than the version in registry") - return false } + + reg.hooksConfig.Logger.Debug().Str("name", name).Str("version", version).Msg( + "Supplied plugin version is greater than the version in registry") + return false } }